From bf0d34e9cfc334bc0c6be389c8c3d6ab7a5c2eff Mon Sep 17 00:00:00 2001 From: Koitharu Date: Tue, 23 May 2023 09:04:57 +0300 Subject: [PATCH 01/94] Validate header value in settings --- .../kotatsu/settings/HeaderValidator.kt | 27 +++++++++++++++++++ .../kotatsu/settings/SourceSettingsExt.kt | 2 +- app/src/main/res/values/strings.xml | 1 + 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/koitharu/kotatsu/settings/HeaderValidator.kt diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/HeaderValidator.kt b/app/src/main/java/org/koitharu/kotatsu/settings/HeaderValidator.kt new file mode 100644 index 000000000..9e251c0a7 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/settings/HeaderValidator.kt @@ -0,0 +1,27 @@ +package org.koitharu.kotatsu.settings + +import okhttp3.Headers +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.network.CommonHeaders +import org.koitharu.kotatsu.utils.EditTextValidator + +class HeaderValidator : EditTextValidator() { + + private val headers = Headers.Builder() + + override fun validate(text: String): ValidationResult { + val trimmed = text.trim() + if (trimmed.isEmpty()) { + return ValidationResult.Success + } + return if (!validateImpl(trimmed)) { + ValidationResult.Failed(context.getString(R.string.invalid_value_message)) + } else { + ValidationResult.Success + } + } + + private fun validateImpl(value: String): Boolean = runCatching { + headers[CommonHeaders.USER_AGENT] = value + }.isSuccess +} diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsExt.kt b/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsExt.kt index 5137fe95e..293f4847d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsExt.kt @@ -44,7 +44,7 @@ fun PreferenceFragmentCompat.addPreferencesFromRepository(repository: RemoteMang EditTextBindListener( inputType = EditorInfo.TYPE_CLASS_TEXT, hint = key.defaultValue, - validator = null, + validator = HeaderValidator(), ), ) setTitle(R.string.user_agent) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 406703d2e..6521d51d0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -416,4 +416,5 @@ Do you want to receive personalized manga suggestions? Translations WebView not available: check if WebView provider is installed + Invalid value From 5108f4511145e50f8ec12777a8486b4ee47ef01f Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 20 May 2023 15:47:47 +0300 Subject: [PATCH 02/94] Limit lifetime of memory content cache --- .../kotatsu/core/cache/DeferredLruCache.kt | 5 --- .../kotatsu/core/cache/ExpiringLruCache.kt | 33 ++++++++++++++++++ .../kotatsu/core/cache/ExpiringValue.kt | 34 +++++++++++++++++++ .../kotatsu/core/cache/MemoryContentCache.kt | 15 ++++---- 4 files changed, 75 insertions(+), 12 deletions(-) delete mode 100644 app/src/main/java/org/koitharu/kotatsu/core/cache/DeferredLruCache.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringLruCache.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringValue.kt diff --git a/app/src/main/java/org/koitharu/kotatsu/core/cache/DeferredLruCache.kt b/app/src/main/java/org/koitharu/kotatsu/core/cache/DeferredLruCache.kt deleted file mode 100644 index 8b9e08aa3..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/core/cache/DeferredLruCache.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.koitharu.kotatsu.core.cache - -import androidx.collection.LruCache - -class DeferredLruCache(maxSize: Int) : LruCache>(maxSize) diff --git a/app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringLruCache.kt b/app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringLruCache.kt new file mode 100644 index 000000000..34d46dfca --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringLruCache.kt @@ -0,0 +1,33 @@ +package org.koitharu.kotatsu.core.cache + +import androidx.collection.LruCache +import java.util.concurrent.TimeUnit + +class ExpiringLruCache( + val maxSize: Int, + private val lifetime: Long, + private val timeUnit: TimeUnit, +) { + + private val cache = LruCache>(maxSize) + + operator fun get(key: ContentCache.Key): T? { + val value = cache.get(key) ?: return null + if (value.isExpired) { + cache.remove(key) + } + return value.get() + } + + operator fun set(key: ContentCache.Key, value: T) { + cache.put(key, ExpiringValue(value, lifetime, timeUnit)) + } + + fun clear() { + cache.evictAll() + } + + fun trimToSize(size: Int) { + cache.trimToSize(size) + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringValue.kt b/app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringValue.kt new file mode 100644 index 000000000..2d561bb0c --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/cache/ExpiringValue.kt @@ -0,0 +1,34 @@ +package org.koitharu.kotatsu.core.cache + +import android.os.SystemClock +import java.util.concurrent.TimeUnit + +class ExpiringValue( + private val value: T, + lifetime: Long, + timeUnit: TimeUnit, +) { + + private val expiresAt = SystemClock.elapsedRealtime() + timeUnit.toMillis(lifetime) + + val isExpired: Boolean + get() = SystemClock.elapsedRealtime() >= expiresAt + + fun get(): T? = if (isExpired) null else value + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ExpiringValue<*> + + if (value != other.value) return false + return expiresAt == other.expiresAt + } + + override fun hashCode(): Int { + var result = value?.hashCode() ?: 0 + result = 31 * result + expiresAt.hashCode() + return result + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/core/cache/MemoryContentCache.kt b/app/src/main/java/org/koitharu/kotatsu/core/cache/MemoryContentCache.kt index ffa9a904e..722b06d41 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/cache/MemoryContentCache.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/cache/MemoryContentCache.kt @@ -6,6 +6,7 @@ import android.content.res.Configuration import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaSource +import java.util.concurrent.TimeUnit class MemoryContentCache(application: Application) : ContentCache, ComponentCallbacks2 { @@ -13,8 +14,8 @@ class MemoryContentCache(application: Application) : ContentCache, ComponentCall application.registerComponentCallbacks(this) } - private val detailsCache = DeferredLruCache(4) - private val pagesCache = DeferredLruCache>(4) + private val detailsCache = ExpiringLruCache>(4, 5, TimeUnit.MINUTES) + private val pagesCache = ExpiringLruCache>>(4, 10, TimeUnit.MINUTES) override val isCachingEnabled: Boolean = true @@ -23,7 +24,7 @@ class MemoryContentCache(application: Application) : ContentCache, ComponentCall } override fun putDetails(source: MangaSource, url: String, details: SafeDeferred) { - detailsCache.put(ContentCache.Key(source, url), details) + detailsCache[ContentCache.Key(source, url)] = details } override suspend fun getPages(source: MangaSource, url: String): List? { @@ -31,7 +32,7 @@ class MemoryContentCache(application: Application) : ContentCache, ComponentCall } override fun putPages(source: MangaSource, url: String, pages: SafeDeferred>) { - pagesCache.put(ContentCache.Key(source, url), pages) + pagesCache[ContentCache.Key(source, url)] = pages } override fun onConfigurationChanged(newConfig: Configuration) = Unit @@ -43,17 +44,17 @@ class MemoryContentCache(application: Application) : ContentCache, ComponentCall trimCache(pagesCache, level) } - private fun trimCache(cache: DeferredLruCache<*>, level: Int) { + private fun trimCache(cache: ExpiringLruCache<*>, level: Int) { when (level) { ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL, ComponentCallbacks2.TRIM_MEMORY_COMPLETE, - ComponentCallbacks2.TRIM_MEMORY_MODERATE -> cache.evictAll() + ComponentCallbacks2.TRIM_MEMORY_MODERATE -> cache.clear() ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN, ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW, ComponentCallbacks2.TRIM_MEMORY_BACKGROUND -> cache.trimToSize(1) - else -> cache.trimToSize(cache.maxSize() / 2) + else -> cache.trimToSize(cache.maxSize / 2) } } } From 8323d399ff89e579a9799d3efcdf6bd1a66e0ff5 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Fri, 19 May 2023 15:31:14 +0300 Subject: [PATCH 03/94] Fix focus changes on sync authorization screen --- .../main/java/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt b/app/src/main/java/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt index cf24fb7b9..b4bf3a2a6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt @@ -84,12 +84,14 @@ class SyncAuthActivity : BaseActivity(), View.OnClickLi binding.groupLogin.isVisible = false binding.groupPassword.isVisible = true pageBackCallback.update() + binding.editPassword.requestFocus() } R.id.button_back -> { binding.groupPassword.isVisible = false binding.groupLogin.isVisible = true pageBackCallback.update() + binding.editEmail.requestFocus() } R.id.button_done -> { @@ -200,6 +202,7 @@ class SyncAuthActivity : BaseActivity(), View.OnClickLi override fun handleOnBackPressed() { binding.groupLogin.isVisible = true binding.groupPassword.isVisible = false + binding.editEmail.requestFocus() update() } From 08e5c148fd0a8fce8fd0ed4474982ef196bd7a6d Mon Sep 17 00:00:00 2001 From: Koitharu Date: Fri, 19 May 2023 14:52:07 +0300 Subject: [PATCH 04/94] Limit cache max-age and action to clear cache manually --- .../org/koitharu/kotatsu/core/AppModule.kt | 11 +++++- .../core/network/CacheLimitInterceptor.kt | 26 +++++++++++++ .../kotatsu/core/network/CommonHeaders.kt | 1 + .../kotatsu/core/prefs/AppSettings.kt | 1 + .../settings/HistorySettingsFragment.kt | 38 +++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/pref_history.xml | 6 +++ 7 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/org/koitharu/kotatsu/core/network/CacheLimitInterceptor.kt diff --git a/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt b/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt index 6797915b1..97542c58d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt @@ -23,6 +23,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.asSharedFlow +import okhttp3.Cache import okhttp3.CookieJar import okhttp3.OkHttpClient import org.koitharu.kotatsu.BuildConfig @@ -88,14 +89,19 @@ interface AppModule { @Provides @Singleton - fun provideOkHttpClient( + fun provideHttpCache( localStorageManager: LocalStorageManager, + ): Cache = localStorageManager.createHttpCache() + + @Provides + @Singleton + fun provideOkHttpClient( + cache: Cache, commonHeadersInterceptor: CommonHeadersInterceptor, mirrorSwitchInterceptor: MirrorSwitchInterceptor, cookieJar: CookieJar, settings: AppSettings, ): OkHttpClient { - val cache = localStorageManager.createHttpCache() return OkHttpClient.Builder().apply { connectTimeout(20, TimeUnit.SECONDS) readTimeout(60, TimeUnit.SECONDS) @@ -106,6 +112,7 @@ interface AppModule { bypassSSLErrors() } cache(cache) + addNetworkInterceptor(CacheLimitInterceptor()) addInterceptor(GZipInterceptor()) addInterceptor(commonHeadersInterceptor) addInterceptor(CloudFlareInterceptor()) diff --git a/app/src/main/java/org/koitharu/kotatsu/core/network/CacheLimitInterceptor.kt b/app/src/main/java/org/koitharu/kotatsu/core/network/CacheLimitInterceptor.kt new file mode 100644 index 000000000..52710c57b --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/network/CacheLimitInterceptor.kt @@ -0,0 +1,26 @@ +package org.koitharu.kotatsu.core.network + +import okhttp3.CacheControl +import okhttp3.Interceptor +import okhttp3.Response +import java.util.concurrent.TimeUnit + +class CacheLimitInterceptor : Interceptor { + + private val defaultMaxAge = TimeUnit.HOURS.toSeconds(1) + private val defaultCacheControl = CacheControl.Builder() + .maxAge(defaultMaxAge.toInt(), TimeUnit.SECONDS) + .build() + .toString() + + override fun intercept(chain: Interceptor.Chain): Response { + val response = chain.proceed(chain.request()) + val responseCacheControl = CacheControl.parse(response.headers) + if (responseCacheControl.noStore || responseCacheControl.maxAgeSeconds <= defaultMaxAge) { + return response + } + return response.newBuilder() + .header(CommonHeaders.CACHE_CONTROL, defaultCacheControl) + .build() + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/core/network/CommonHeaders.kt b/app/src/main/java/org/koitharu/kotatsu/core/network/CommonHeaders.kt index 943e08f2e..f8976acd6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/network/CommonHeaders.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/network/CommonHeaders.kt @@ -13,6 +13,7 @@ object CommonHeaders { const val CONTENT_ENCODING = "Content-Encoding" const val ACCEPT_ENCODING = "Accept-Encoding" const val AUTHORIZATION = "Authorization" + const val CACHE_CONTROL = "Cache-Control" val CACHE_CONTROL_NO_STORE: CacheControl get() = CacheControl.Builder().noStore().build() diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt index 6dab7e362..dc13b7abb 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -345,6 +345,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { const val KEY_SOURCES_HIDDEN = "sources_hidden" const val KEY_TRAFFIC_WARNING = "traffic_warning" const val KEY_PAGES_CACHE_CLEAR = "pages_cache_clear" + const val KEY_HTTP_CACHE_CLEAR = "http_cache_clear" const val KEY_COOKIES_CLEAR = "cookies_clear" const val KEY_THUMBS_CACHE_CLEAR = "thumbs_cache_clear" const val KEY_SEARCH_HISTORY_CLEAR = "search_history_clear" diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt index c0b53620a..82f6bc441 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt @@ -8,7 +8,10 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.runInterruptible +import okhttp3.Cache import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BasePreferenceFragment import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar @@ -39,6 +42,9 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach @Inject lateinit var cookieJar: MutableCookieJar + @Inject + lateinit var cache: Cache + @Inject lateinit var shortcutsUpdater: ShortcutsUpdater @@ -52,6 +58,7 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach super.onViewCreated(view, savedInstanceState) findPreference(AppSettings.KEY_PAGES_CACHE_CLEAR)?.bindSummaryToCacheSize(CacheDir.PAGES) findPreference(AppSettings.KEY_THUMBS_CACHE_CLEAR)?.bindSummaryToCacheSize(CacheDir.THUMBS) + findPreference(AppSettings.KEY_HTTP_CACHE_CLEAR)?.bindSummaryToHttpCacheSize() findPreference(AppSettings.KEY_SEARCH_HISTORY_CLEAR)?.let { pref -> viewLifecycleScope.launch { lifecycle.awaitStateAtLeast(Lifecycle.State.RESUMED) @@ -90,6 +97,11 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach true } + AppSettings.KEY_HTTP_CACHE_CLEAR -> { + clearHttpCache() + true + } + AppSettings.KEY_UPDATES_FEED_CLEAR -> { viewLifecycleScope.launch { trackerRepo.clearLogs() @@ -131,6 +143,32 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach summary = FileSize.BYTES.format(context, size) } + private fun Preference.bindSummaryToHttpCacheSize() = viewLifecycleScope.launch { + val size = runInterruptible(Dispatchers.IO) { cache.size() } + summary = FileSize.BYTES.format(context, size) + } + + private fun clearHttpCache() { + val preference = findPreference(AppSettings.KEY_HTTP_CACHE_CLEAR) ?: return + val ctx = preference.context.applicationContext + viewLifecycleScope.launch { + try { + preference.isEnabled = false + val size = runInterruptible(Dispatchers.IO) { + cache.evictAll() + cache.size() + } + preference.summary = FileSize.BYTES.format(ctx, size) + } catch (e: CancellationException) { + throw e + } catch (e: Exception) { + preference.summary = e.getDisplayMessage(ctx.resources) + } finally { + preference.isEnabled = true + } + } + } + private fun clearSearchHistory(preference: Preference) { MaterialAlertDialogBuilder(context ?: return) .setTitle(R.string.clear_search_history) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6521d51d0..c92e6527d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -417,4 +417,5 @@ Translations WebView not available: check if WebView provider is installed Invalid value + Clear network cache diff --git a/app/src/main/res/xml/pref_history.xml b/app/src/main/res/xml/pref_history.xml index a7304418c..de6088bc8 100644 --- a/app/src/main/res/xml/pref_history.xml +++ b/app/src/main/res/xml/pref_history.xml @@ -39,6 +39,12 @@ android:summary="@string/computing_" android:title="@string/clear_pages_cache" /> + + Date: Tue, 23 May 2023 13:05:37 +0300 Subject: [PATCH 05/94] Update parsers --- app/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index aa5621fc1..24a9609d1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdkVersion 21 targetSdkVersion 33 - versionCode 545 - versionName '5.1.1' + versionCode 546 + versionName '5.1.2' generatedDensities = [] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -78,7 +78,7 @@ afterEvaluate { } dependencies { //noinspection GradleDependency - implementation('com.github.KotatsuApp:kotatsu-parsers:cae7073f87') { + implementation('com.github.KotatsuApp:kotatsu-parsers:ebcc6391d6') { exclude group: 'org.json', module: 'json' } From dc358ae6a21635b2a58bac88a9eb76a06eab32d1 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 24 May 2023 11:52:09 +0300 Subject: [PATCH 06/94] Refactor manga loading --- .../kotatsu/core/model/DoubleManga.kt | 76 ++++++++ .../org/koitharu/kotatsu/core/model/Manga.kt | 4 + .../kotatsu/core/parser/MangaIntent.kt | 11 +- .../details/domain/DetailsInteractor.kt | 94 ++++++++++ .../kotatsu/details/ui/ChaptersFragment.kt | 12 +- .../kotatsu/details/ui/ChaptersMapper.kt | 2 +- .../kotatsu/details/ui/DetailsViewModel.kt | 175 +++++++----------- .../details/ui/MangaDetailsDelegate.kt | 89 --------- .../history/domain/HistoryRepository.kt | 15 -- .../kotatsu/local/domain/DoubleMangaLoader.kt | 66 +++++++ .../local/domain/LocalMangaRepository.kt | 8 +- .../kotatsu/reader/domain/ChaptersLoader.kt | 28 ++- .../kotatsu/reader/ui/ReaderActivity.kt | 2 +- .../kotatsu/reader/ui/ReaderViewModel.kt | 71 +++---- .../ui/config/ReaderConfigBottomSheet.kt | 2 +- .../ui/thumbnails/PagesThumbnailsViewModel.kt | 16 +- app/src/main/res/raw/tags_redlist | 3 + 17 files changed, 397 insertions(+), 277 deletions(-) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/model/DoubleManga.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/details/ui/MangaDetailsDelegate.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/local/domain/DoubleMangaLoader.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/DoubleManga.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/DoubleManga.kt new file mode 100644 index 000000000..460286fa1 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/DoubleManga.kt @@ -0,0 +1,76 @@ +package org.koitharu.kotatsu.core.model + +import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.parsers.model.MangaChapter +import org.koitharu.kotatsu.parsers.model.MangaSource +import org.koitharu.kotatsu.reader.data.filterChapters + +data class DoubleManga( + private val remoteManga: Result?, + private val localManga: Result?, +) { + + constructor(manga: Manga) : this( + remoteManga = if (manga.source != MangaSource.LOCAL) Result.success(manga) else null, + localManga = if (manga.source == MangaSource.LOCAL) Result.success(manga) else null, + ) + + val remote: Manga? + get() = remoteManga?.getOrNull() + + val local: Manga? + get() = localManga?.getOrNull() + + val any: Manga? + get() = remote ?: local + + val hasRemote: Boolean + get() = remoteManga?.isSuccess == true + + val hasLocal: Boolean + get() = localManga?.isSuccess == true + + val chapters: List? by lazy(LazyThreadSafetyMode.PUBLICATION) { + mergeChapters() + } + + fun requireAny(): Manga { + val result = remoteManga?.getOrNull() ?: localManga?.getOrNull() + if (result != null) { + return result + } + throw ( + remoteManga?.exceptionOrNull() + ?: localManga?.exceptionOrNull() + ?: IllegalStateException("No online either local manga available") + ) + } + + fun filterChapters(branch: String?) = DoubleManga( + remoteManga?.map { it.filterChapters(branch) }, + localManga?.map { it.filterChapters(branch) }, + ) + + private fun mergeChapters(): List? { + val remoteChapters = remote?.chapters + val localChapters = local?.chapters + if (localChapters == null && remoteChapters == null) { + return null + } + val localMap = if (!localChapters.isNullOrEmpty()) { + localChapters.associateByTo(LinkedHashMap(localChapters.size)) { it.id } + } else { + null + } + val result = ArrayList(maxOf(remoteChapters?.size ?: 0, localChapters?.size ?: 0)) + remoteChapters?.forEach { r -> + localMap?.remove(r.id)?.let { l -> + result.add(l) + } ?: result.add(r) + } + localMap?.values?.let { + result.addAll(it) + } + return result + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/Manga.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/Manga.kt index 4ed4c7885..cbfc5e1f8 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/Manga.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/Manga.kt @@ -5,6 +5,7 @@ import org.koitharu.kotatsu.core.util.ext.iterator import org.koitharu.kotatsu.details.ui.model.ChapterListItem import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter +import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.util.mapToSet fun Collection.ids() = mapToSet { it.id } @@ -54,3 +55,6 @@ fun Manga.getPreferredBranch(history: MangaHistory?): String? { } return candidates.ifEmpty { groups }.maxByOrNull { it.value.size }?.key } + +val Manga.isLocal: Boolean + get() = source == MangaSource.LOCAL diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaIntent.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaIntent.kt index 5c3d54a17..8ab582147 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaIntent.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaIntent.kt @@ -12,28 +12,31 @@ import org.koitharu.kotatsu.parsers.model.Manga class MangaIntent private constructor( @JvmField val manga: Manga?, - @JvmField val mangaId: Long, + @JvmField val id: Long, @JvmField val uri: Uri?, ) { constructor(intent: Intent?) : this( manga = intent?.getParcelableExtraCompat(KEY_MANGA)?.manga, - mangaId = intent?.getLongExtra(KEY_ID, ID_NONE) ?: ID_NONE, + id = intent?.getLongExtra(KEY_ID, ID_NONE) ?: ID_NONE, uri = intent?.data, ) constructor(savedStateHandle: SavedStateHandle) : this( manga = savedStateHandle.get(KEY_MANGA)?.manga, - mangaId = savedStateHandle[KEY_ID] ?: ID_NONE, + id = savedStateHandle[KEY_ID] ?: ID_NONE, uri = savedStateHandle[BaseActivity.EXTRA_DATA], ) constructor(args: Bundle?) : this( manga = args?.getParcelableCompat(KEY_MANGA)?.manga, - mangaId = args?.getLong(KEY_ID, ID_NONE) ?: ID_NONE, + id = args?.getLong(KEY_ID, ID_NONE) ?: ID_NONE, uri = null, ) + val mangaId: Long + get() = if (id != ID_NONE) id else manga?.id ?: uri?.lastPathSegment?.toLongOrNull() ?: ID_NONE + companion object { const val ID_NONE = 0L diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt new file mode 100644 index 000000000..3968e4399 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt @@ -0,0 +1,94 @@ +package org.koitharu.kotatsu.details.domain + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChangedBy +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import org.koitharu.kotatsu.core.model.DoubleManga +import org.koitharu.kotatsu.core.model.isLocal +import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.core.prefs.observeAsFlow +import org.koitharu.kotatsu.favourites.domain.FavouritesRepository +import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.local.data.LocalManga +import org.koitharu.kotatsu.local.domain.LocalMangaRepository +import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.parsers.util.runCatchingCancellable +import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler +import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo +import org.koitharu.kotatsu.tracker.domain.TrackingRepository +import org.koitharu.kotatsu.util.ext.printStackTraceDebug +import java.io.IOException +import javax.inject.Inject + +class DetailsInteractor @Inject constructor( + private val historyRepository: HistoryRepository, + private val favouritesRepository: FavouritesRepository, + private val localMangaRepository: LocalMangaRepository, + private val trackingRepository: TrackingRepository, + private val settings: AppSettings, + private val scrobblers: Set<@JvmSuppressWildcards Scrobbler>, +) { + + fun observeIsFavourite(mangaId: Long): Flow { + return favouritesRepository.observeCategoriesIds(mangaId) + .map { it.isNotEmpty() } + } + + fun observeNewChapters(mangaId: Long): Flow { + return settings.observeAsFlow(AppSettings.KEY_TRACKER_ENABLED) { isTrackerEnabled } + .flatMapLatest { isEnabled -> + if (isEnabled) { + trackingRepository.observeNewChaptersCount(mangaId) + } else { + flowOf(0) + } + } + } + + fun observeScrobblingInfo(mangaId: Long): Flow> { + return combine( + scrobblers.map { it.observeScrobblingInfo(mangaId) }, + ) { scrobblingInfo -> + scrobblingInfo.filterNotNull() + } + } + + suspend fun deleteLocalManga(manga: Manga) { + val victim = if (manga.isLocal) manga else localMangaRepository.findSavedManga(manga)?.manga + checkNotNull(victim) { "Cannot find saved manga for ${manga.title}" } + val original = if (manga.isLocal) localMangaRepository.getRemoteManga(manga) else manga + localMangaRepository.delete(victim) || throw IOException("Unable to delete file") + runCatchingCancellable { + historyRepository.deleteOrSwap(victim, original) + }.onFailure { + it.printStackTraceDebug() + } + } + + fun observeIncognitoMode(mangaFlow: Flow): Flow { + return mangaFlow + .distinctUntilChangedBy { it?.isNsfw } + .flatMapLatest { manga -> + if (manga != null) { + historyRepository.observeShouldSkip(manga) + } else { + settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled } + } + } + } + + suspend fun updateLocal(subject: DoubleManga?, localManga: LocalManga): DoubleManga? { + return if (subject?.any?.id == localManga.manga.id) { + subject.copy( + localManga = runCatchingCancellable { + localMangaRepository.getDetails(localManga.manga) + }, + ) + } else { + subject + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt index e82993114..e3b3c1e64 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt @@ -160,12 +160,14 @@ class ChaptersFragment : val selectedIds = selectionController?.peekCheckedIds() ?: return false val allItems = chaptersAdapter?.items.orEmpty() val items = allItems.withIndex().filter { (_, x) -> x.chapter.id in selectedIds } - menu.findItem(R.id.action_save).isVisible = items.none { (_, x) -> - x.chapter.source == MangaSource.LOCAL - } - menu.findItem(R.id.action_delete).isVisible = items.all { (_, x) -> - x.chapter.source == MangaSource.LOCAL + var canSave = true + var canDelete = true + items.forEach { (_, x) -> + val isLocal = x.isDownloaded || x.chapter.source == MangaSource.LOCAL + if (isLocal) canSave = false else canDelete = false } + menu.findItem(R.id.action_save).isVisible = canSave + menu.findItem(R.id.action_delete).isVisible = canDelete menu.findItem(R.id.action_select_all).isVisible = items.size < allItems.size menu.findItem(R.id.action_mark_current).isVisible = items.size == 1 mode.title = items.size.toString() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersMapper.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersMapper.kt index 618d623e1..27a937c0c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersMapper.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersMapper.kt @@ -52,7 +52,7 @@ fun mapChapters( isCurrent = chapter.id == currentId, isUnread = isUnread, isNew = false, - isDownloaded = false, + isDownloaded = remoteManga != null, ) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt index 0d3101f28..927e9b80c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt @@ -8,6 +8,7 @@ import androidx.core.net.toUri import androidx.core.text.getSpans import androidx.core.text.parseAsHtml import androidx.lifecycle.LiveData +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asFlow import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope @@ -25,82 +26,74 @@ import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transformLatest -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.update import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository +import org.koitharu.kotatsu.core.model.DoubleManga +import org.koitharu.kotatsu.core.model.getPreferredBranch +import org.koitharu.kotatsu.core.parser.MangaIntent import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.observeAsFlow import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.util.SingleLiveEvent import org.koitharu.kotatsu.core.util.asFlowLiveData import org.koitharu.kotatsu.core.util.ext.computeSize +import org.koitharu.kotatsu.core.util.ext.requireValue import org.koitharu.kotatsu.core.util.ext.toFileOrNull import org.koitharu.kotatsu.details.domain.BranchComparator +import org.koitharu.kotatsu.details.domain.DetailsInteractor import org.koitharu.kotatsu.details.ui.model.ChapterListItem import org.koitharu.kotatsu.details.ui.model.HistoryInfo import org.koitharu.kotatsu.details.ui.model.MangaBranch import org.koitharu.kotatsu.download.ui.worker.DownloadWorker -import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.history.domain.HistoryRepository import org.koitharu.kotatsu.local.data.LocalManga import org.koitharu.kotatsu.local.data.LocalStorageChanges -import org.koitharu.kotatsu.local.domain.LocalMangaRepository +import org.koitharu.kotatsu.local.domain.DoubleMangaLoader import org.koitharu.kotatsu.parsers.model.Manga -import org.koitharu.kotatsu.parsers.model.MangaSource -import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus -import org.koitharu.kotatsu.tracker.domain.TrackingRepository -import org.koitharu.kotatsu.util.ext.printStackTraceDebug -import java.io.IOException import javax.inject.Inject @HiltViewModel class DetailsViewModel @Inject constructor( private val historyRepository: HistoryRepository, - favouritesRepository: FavouritesRepository, - private val localMangaRepository: LocalMangaRepository, - trackingRepository: TrackingRepository, private val bookmarksRepository: BookmarksRepository, private val settings: AppSettings, private val scrobblers: Set<@JvmSuppressWildcards Scrobbler>, private val imageGetter: Html.ImageGetter, - private val delegate: MangaDetailsDelegate, @LocalStorageChanges private val localStorageChanges: SharedFlow, private val downloadScheduler: DownloadWorker.Scheduler, + private val interactor: DetailsInteractor, + savedStateHandle: SavedStateHandle, + private val mangaLoader: DoubleMangaLoader, ) : BaseViewModel() { + private val intent = MangaIntent(savedStateHandle) + private val mangaId = intent.mangaId + private val doubleManga: MutableStateFlow = MutableStateFlow(intent.manga?.let { DoubleManga(it) }) private var loadingJob: Job val onShowToast = SingleLiveEvent() val onDownloadStarted = SingleLiveEvent() - private val mangaData = combine( - delegate.onlineManga, - delegate.localManga, - ) { o, l -> - o ?: l - }.stateIn(viewModelScope, SharingStarted.Lazily, null) + private val mangaData = doubleManga.map { it?.any } + .stateIn(viewModelScope, SharingStarted.Eagerly, doubleManga.value?.any) - private val history = historyRepository.observeOne(delegate.mangaId) + private val history = historyRepository.observeOne(mangaId) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null) - private val favourite = favouritesRepository.observeCategoriesIds(delegate.mangaId).map { it.isNotEmpty() } + private val favourite = interactor.observeIsFavourite(mangaId) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false) - private val newChapters = settings.observeAsFlow(AppSettings.KEY_TRACKER_ENABLED) { isTrackerEnabled } - .flatMapLatest { isEnabled -> - if (isEnabled) { - trackingRepository.observeNewChaptersCount(delegate.mangaId) - } else { - flowOf(0) - } - }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, 0) + private val newChapters = interactor.observeNewChapters(mangaId) + .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, 0) private val chaptersQuery = MutableStateFlow("") + private val selectedBranch = MutableStateFlow(null) private val chaptersReversed = settings.observeAsFlow(AppSettings.KEY_REVERSE_CHAPTERS) { chaptersReverse } .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false) @@ -112,9 +105,9 @@ class DetailsViewModel @Inject constructor( val historyInfo: LiveData = combine( mangaData, - delegate.selectedBranch, + selectedBranch, history, - historyRepository.observeShouldSkip(mangaData), + interactor.observeIncognitoMode(mangaData), ) { m, b, h, im -> HistoryInfo(m, b, h, im) }.asFlowLiveData( @@ -126,10 +119,11 @@ class DetailsViewModel @Inject constructor( if (it != null) bookmarksRepository.observeBookmarks(it) else flowOf(emptyList()) }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) - val localSize = delegate.localManga + val localSize = doubleManga .map { - if (it != null) { - val file = it.url.toUri().toFileOrNull() + val local = it?.local + if (local != null) { + val file = local.url.toUri().toFileOrNull() file?.computeSize() ?: 0L } else { 0L @@ -152,46 +146,38 @@ class DetailsViewModel @Inject constructor( val isScrobblingAvailable: Boolean get() = scrobblers.any { it.isAvailable } - val scrobblingInfo: LiveData> = combine( - scrobblers.map { it.observeScrobblingInfo(delegate.mangaId) }, - ) { scrobblingInfo -> - scrobblingInfo.filterNotNull() - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) + val scrobblingInfo: LiveData> = interactor.observeScrobblingInfo(mangaId) + .asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) val branches: LiveData> = combine( - delegate.onlineManga, - delegate.localManga, - delegate.selectedBranch, - ) { m, l, b -> - val chapters = concat(m?.chapters, l?.chapters) - if (chapters.isEmpty()) return@combine emptyList() + doubleManga, + selectedBranch, + ) { m, b -> + val chapters = m?.chapters + if (chapters.isNullOrEmpty()) return@combine emptyList() chapters.groupBy { x -> x.branch } .map { x -> MangaBranch(x.key, x.value.size, x.key == b) } .sortedWith(BranchComparator()) }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) - val selectedBranchName = delegate.selectedBranch + val selectedBranchName = selectedBranch .asFlowLiveData(viewModelScope.coroutineContext, null) val isChaptersEmpty: LiveData = combine( - delegate.onlineManga, - delegate.localManga, + doubleManga, isLoading.asFlow(), - ) { manga, local, loading -> - (manga != null && manga.chapters.isNullOrEmpty()) && - (local != null && local.chapters.isNullOrEmpty()) && - !loading + ) { manga, loading -> + manga?.any != null && manga.chapters.isNullOrEmpty() && !loading }.asFlowLiveData(viewModelScope.coroutineContext, false) val chapters = combine( combine( - delegate.onlineManga, - delegate.localManga, + doubleManga, history, - delegate.selectedBranch, + selectedBranch, newChapters, - ) { manga, local, history, branch, news -> - mapChapters(manga, local, history, news, branch) + ) { manga, history, branch, news -> + mapChapters(manga?.remote, manga?.local, history, news, branch) }, chaptersReversed, chaptersQuery, @@ -200,7 +186,7 @@ class DetailsViewModel @Inject constructor( }.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default) val selectedBranchValue: String? - get() = delegate.selectedBranch.value + get() = selectedBranch.value init { loadingJob = doLoad() @@ -216,20 +202,14 @@ class DetailsViewModel @Inject constructor( } fun deleteLocal() { - val m = delegate.localManga.value + val m = doubleManga.value?.local if (m == null) { onShowToast.call(R.string.file_not_found) return } launchLoadingJob(Dispatchers.Default) { - val manga = if (m.source == MangaSource.LOCAL) m else localMangaRepository.findSavedManga(m)?.manga - checkNotNull(manga) { "Cannot find saved manga for ${m.title}" } - val original = localMangaRepository.getRemoteManga(manga) - localMangaRepository.delete(manga) || throw IOException("Unable to delete file") - runCatchingCancellable { - historyRepository.deleteOrSwap(manga, original) - } - onMangaRemoved.emitCall(manga) + interactor.deleteLocalManga(m) + onMangaRemoved.emitCall(m) } } @@ -245,11 +225,7 @@ class DetailsViewModel @Inject constructor( } fun setSelectedBranch(branch: String?) { - delegate.selectedBranch.value = branch - } - - fun getRemoteManga(): Manga? { - return delegate.onlineManga.value + selectedBranch.value = branch } fun performChapterSearch(query: String?) { @@ -260,7 +236,7 @@ class DetailsViewModel @Inject constructor( val scrobbler = getScrobbler(index) ?: return launchJob(Dispatchers.Default) { scrobbler.updateScrobblingInfo( - mangaId = delegate.mangaId, + mangaId = mangaId, rating = rating, status = status, comment = null, @@ -272,26 +248,32 @@ class DetailsViewModel @Inject constructor( val scrobbler = getScrobbler(index) ?: return launchJob(Dispatchers.Default) { scrobbler.unregisterScrobbling( - mangaId = delegate.mangaId, + mangaId = mangaId, ) } } fun markChapterAsCurrent(chapterId: Long) { launchJob(Dispatchers.Default) { - val manga = checkNotNull(mangaData.value) - val chapters = checkNotNull(manga.getChapters(selectedBranchValue)) + val manga = checkNotNull(doubleManga.value) + val chapters = checkNotNull(manga.filterChapters(selectedBranchValue).chapters) val chapterIndex = chapters.indexOfFirst { it.id == chapterId } check(chapterIndex in chapters.indices) { "Chapter not found" } val percent = chapterIndex / chapters.size.toFloat() - historyRepository.addOrUpdate(manga = manga, chapterId = chapterId, page = 0, scroll = 0, percent = percent) + historyRepository.addOrUpdate( + manga = manga.requireAny(), + chapterId = chapterId, + page = 0, + scroll = 0, + percent = percent, + ) } } fun download(chaptersIds: Set?) { launchJob(Dispatchers.Default) { downloadScheduler.schedule( - delegate.onlineManga.value ?: checkNotNull(manga.value), + doubleManga.requireValue().requireAny(), chaptersIds, ) onDownloadStarted.emitCall(Unit) @@ -299,7 +281,12 @@ class DetailsViewModel @Inject constructor( } private fun doLoad() = launchLoadingJob(Dispatchers.Default) { - delegate.doLoad() + val result = mangaLoader.load(intent) + val manga = result.requireAny() + // find default branch + val hist = historyRepository.getOne(manga) + selectedBranch.value = manga.getPreferredBranch(hist) + doubleManga.value = result } private fun List.filterSearch(query: String): List { @@ -313,21 +300,9 @@ class DetailsViewModel @Inject constructor( private suspend fun onDownloadComplete(downloadedManga: LocalManga?) { downloadedManga ?: return - val currentManga = mangaData.value ?: return - if (currentManga.id != downloadedManga.manga.id) { - return - } - if (currentManga.source == MangaSource.LOCAL) { - reload() - } else { - viewModelScope.launch(Dispatchers.Default) { - runCatchingCancellable { - localMangaRepository.getDetails(downloadedManga.manga) - }.onSuccess { - delegate.publishManga(it) - }.onFailure { - it.printStackTraceDebug() - } + launchJob { + doubleManga.update { + interactor.updateLocal(it, downloadedManga) } } } @@ -353,18 +328,4 @@ class DetailsViewModel @Inject constructor( } return scrobbler } - - private fun concat(a: List?, b: List?): List { - return when { - a == null && b == null -> emptyList() - a == null && b != null -> b - a != null && b == null -> a - a != null && b != null -> buildList(a.size + b.size) { - addAll(a) - addAll(b) - } - - else -> error("This shouldn't have happened") - } - } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/MangaDetailsDelegate.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/MangaDetailsDelegate.kt deleted file mode 100644 index eee5e04e6..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/MangaDetailsDelegate.kt +++ /dev/null @@ -1,89 +0,0 @@ -package org.koitharu.kotatsu.details.ui - -import androidx.lifecycle.SavedStateHandle -import dagger.hilt.android.ViewModelLifecycle -import dagger.hilt.android.scopes.ViewModelScoped -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.stateIn -import org.koitharu.kotatsu.core.model.getPreferredBranch -import org.koitharu.kotatsu.core.os.NetworkState -import org.koitharu.kotatsu.core.parser.MangaDataRepository -import org.koitharu.kotatsu.core.parser.MangaIntent -import org.koitharu.kotatsu.core.parser.MangaRepository -import org.koitharu.kotatsu.core.util.RetainedLifecycleCoroutineScope -import org.koitharu.kotatsu.history.domain.HistoryRepository -import org.koitharu.kotatsu.local.domain.LocalMangaRepository -import org.koitharu.kotatsu.parsers.exception.NotFoundException -import org.koitharu.kotatsu.parsers.model.Manga -import org.koitharu.kotatsu.parsers.model.MangaSource -import org.koitharu.kotatsu.parsers.util.runCatchingCancellable -import org.koitharu.kotatsu.util.ext.printStackTraceDebug -import javax.inject.Inject - -@ViewModelScoped -class MangaDetailsDelegate @Inject constructor( - savedStateHandle: SavedStateHandle, - lifecycle: ViewModelLifecycle, - private val mangaDataRepository: MangaDataRepository, - private val historyRepository: HistoryRepository, - private val localMangaRepository: LocalMangaRepository, - private val mangaRepositoryFactory: MangaRepository.Factory, - networkState: NetworkState, -) { - private val viewModelScope = RetainedLifecycleCoroutineScope(lifecycle) - - private val intent = MangaIntent(savedStateHandle) - private val onlineMangaStateFlow = MutableStateFlow(null) - private val localMangaStateFlow = MutableStateFlow(null) - - val onlineManga = combine( - onlineMangaStateFlow, - networkState, - ) { m, s -> m.takeIf { s } } - .stateIn(viewModelScope, SharingStarted.Lazily, null) - val localManga = localMangaStateFlow.asStateFlow() - - val selectedBranch = MutableStateFlow(null) - val mangaId = intent.manga?.id ?: intent.mangaId - - init { - intent.manga?.let { - publishManga(it) - } - } - - suspend fun doLoad() { - var manga = mangaDataRepository.resolveIntent(intent) ?: throw NotFoundException("Cannot find manga", "") - publishManga(manga) - manga = mangaRepositoryFactory.create(manga.source).getDetails(manga) - // find default branch - val hist = historyRepository.getOne(manga) - selectedBranch.value = manga.getPreferredBranch(hist) - publishManga(manga) - runCatchingCancellable { - if (manga.source == MangaSource.LOCAL) { - val m = localMangaRepository.getRemoteManga(manga) ?: return@runCatchingCancellable null - mangaRepositoryFactory.create(m.source).getDetails(m) - } else { - localMangaRepository.findSavedManga(manga)?.manga - } - }.onFailure { error -> - error.printStackTraceDebug() - }.onSuccess { - if (it != null) { - publishManga(it) - } - } - } - - fun publishManga(manga: Manga) { - if (manga.source == MangaSource.LOCAL) { - localMangaStateFlow - } else { - onlineMangaStateFlow - }.value = manga - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryRepository.kt index 784f74280..3cc4a81b0 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryRepository.kt @@ -4,9 +4,7 @@ import androidx.room.withTransaction import dagger.Reusable import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.distinctUntilChangedBy import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import org.koitharu.kotatsu.core.db.MangaDatabase @@ -17,7 +15,6 @@ import org.koitharu.kotatsu.core.db.entity.toMangaTag import org.koitharu.kotatsu.core.db.entity.toMangaTags import org.koitharu.kotatsu.core.model.MangaHistory import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.core.prefs.observeAsFlow import org.koitharu.kotatsu.core.ui.util.ReversibleHandle import org.koitharu.kotatsu.core.util.ext.mapItems import org.koitharu.kotatsu.history.data.HistoryEntity @@ -161,18 +158,6 @@ class HistoryRepository @Inject constructor( .distinctUntilChanged() } - fun observeShouldSkip(mangaFlow: Flow): Flow { - return mangaFlow - .distinctUntilChangedBy { it?.isNsfw } - .flatMapLatest { m -> - if (m != null) { - observeShouldSkip(m) - } else { - settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled } - } - } - } - private suspend fun recover(ids: Collection) { db.withTransaction { for (id in ids) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/DoubleMangaLoader.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/DoubleMangaLoader.kt new file mode 100644 index 000000000..5cf8325c1 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/DoubleMangaLoader.kt @@ -0,0 +1,66 @@ +package org.koitharu.kotatsu.local.domain + +import dagger.Reusable +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import org.koitharu.kotatsu.core.model.DoubleManga +import org.koitharu.kotatsu.core.model.isLocal +import org.koitharu.kotatsu.core.parser.MangaDataRepository +import org.koitharu.kotatsu.core.parser.MangaIntent +import org.koitharu.kotatsu.core.parser.MangaRepository +import org.koitharu.kotatsu.parsers.exception.NotFoundException +import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.parsers.util.runCatchingCancellable +import javax.inject.Inject + +@Reusable +class DoubleMangaLoader @Inject constructor( + private val mangaDataRepository: MangaDataRepository, + private val localMangaRepository: LocalMangaRepository, + private val mangaRepositoryFactory: MangaRepository.Factory, +) { + + suspend fun load(manga: Manga): DoubleManga = coroutineScope { + val remoteDeferred = async(Dispatchers.Default) { loadRemote(manga) } + val localDeferred = async(Dispatchers.Default) { loadLocal(manga) } + DoubleManga( + remoteManga = remoteDeferred.await(), + localManga = localDeferred.await(), + ) + } + + suspend fun load(mangaId: Long): DoubleManga { + val manga = mangaDataRepository.findMangaById(mangaId) ?: throwNFE() + return load(manga) + } + + suspend fun load(intent: MangaIntent): DoubleManga { + val manga = mangaDataRepository.resolveIntent(intent) ?: throwNFE() + return load(manga) + } + + private suspend fun loadLocal(manga: Manga): Result? { + return runCatchingCancellable { + if (manga.isLocal) { + localMangaRepository.getDetails(manga) + } else { + localMangaRepository.findSavedManga(manga)?.manga + } ?: return null + } + } + + private suspend fun loadRemote(manga: Manga): Result? { + return runCatchingCancellable { + val seed = if (manga.isLocal) { + localMangaRepository.getRemoteManga(manga) + } else { + manga + } ?: return null + val repository = mangaRepositoryFactory.create(seed.source) + repository.getDetails(seed) + } + } + + private fun throwNFE(): Nothing = throw NotFoundException("Cannot find manga", "") +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt index 9763882a7..6d3964978 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt @@ -11,6 +11,7 @@ import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch import kotlinx.coroutines.runInterruptible +import org.koitharu.kotatsu.core.model.isLocal import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.util.CompositeMutex import org.koitharu.kotatsu.core.util.ext.deleteAwait @@ -99,8 +100,11 @@ class LocalMangaRepository @Inject constructor( suspend fun deleteChapters(manga: Manga, ids: Set) { lockManga(manga.id) try { - LocalMangaUtil(manga).deleteChapters(ids) - localStorageChanges.emit(LocalManga(manga)) + val subject = if (manga.isLocal) manga else checkNotNull(findSavedManga(manga)) { + "Manga is not stored on local storage" + }.manga + LocalMangaUtil(subject).deleteChapters(ids) + localStorageChanges.emit(LocalManga(subject)) } finally { unlockManga(manga.id) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt index 334efab8a..6cff4c94f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt @@ -4,8 +4,8 @@ import android.util.LongSparseArray import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import org.koitharu.kotatsu.core.model.DoubleManga import org.koitharu.kotatsu.core.parser.MangaRepository -import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.reader.ui.pager.ReaderPage import javax.inject.Inject @@ -17,17 +17,27 @@ class ChaptersLoader @Inject constructor( private val mangaRepositoryFactory: MangaRepository.Factory, ) { - val chapters = LongSparseArray() + private val chapters = LongSparseArray() private val chapterPages = ChapterPages() private val mutex = Mutex() - suspend fun loadPrevNextChapter(manga: Manga, currentId: Long, isNext: Boolean) { + val size: Int + get() = chapters.size() + + suspend fun init(manga: DoubleManga) = mutex.withLock { + chapters.clear() + manga.chapters?.forEach { + chapters.put(it.id, it) + } + } + + suspend fun loadPrevNextChapter(manga: DoubleManga, currentId: Long, isNext: Boolean) { val chapters = manga.chapters ?: return val predicate: (MangaChapter) -> Boolean = { it.id == currentId } val index = if (isNext) chapters.indexOfFirst(predicate) else chapters.indexOfLast(predicate) if (index == -1) return val newChapter = chapters.getOrNull(if (isNext) index + 1 else index - 1) ?: return - val newPages = loadChapter(manga, newChapter.id) + val newPages = loadChapter(newChapter.id) mutex.withLock { if (chapterPages.chaptersSize > 1) { // trim pages @@ -47,14 +57,16 @@ class ChaptersLoader @Inject constructor( } } - suspend fun loadSingleChapter(manga: Manga, chapterId: Long) { - val pages = loadChapter(manga, chapterId) + suspend fun loadSingleChapter(chapterId: Long) { + val pages = loadChapter(chapterId) mutex.withLock { chapterPages.clear() chapterPages.addLast(chapterId, pages) } } + fun peekChapter(chapterId: Long): MangaChapter? = chapters[chapterId] + fun getPages(chapterId: Long): List { return chapterPages.subList(chapterId) } @@ -69,9 +81,9 @@ class ChaptersLoader @Inject constructor( fun snapshot() = chapterPages.toList() - private suspend fun loadChapter(manga: Manga, chapterId: Long): List { + private suspend fun loadChapter(chapterId: Long): List { val chapter = checkNotNull(chapters[chapterId]) { "Requested chapter not found" } - val repo = mangaRepositoryFactory.create(manga.source) + val repo = mangaRepositoryFactory.create(chapter.source) return repo.getPages(chapter).mapIndexed { index, page -> ReaderPage(page, index, chapterId) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index 3fff9ab9a..6dfb02e93 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -183,7 +183,7 @@ class ReaderActivity : val state = viewModel.getCurrentState() ?: return false PagesThumbnailsSheet.show( supportFragmentManager, - viewModel.manga ?: return false, + viewModel.manga?.any ?: return false, state.chapterId, state.page, ) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index f092a5c06..029bf76b3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -1,7 +1,6 @@ package org.koitharu.kotatsu.reader.ui import android.net.Uri -import android.util.LongSparseArray import androidx.activity.result.ActivityResultLauncher import androidx.annotation.AnyThread import androidx.annotation.MainThread @@ -16,6 +15,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.ensureActive +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine @@ -33,6 +33,7 @@ import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository +import org.koitharu.kotatsu.core.model.DoubleManga import org.koitharu.kotatsu.core.os.ShortcutsUpdater import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.parser.MangaIntent @@ -50,12 +51,11 @@ import org.koitharu.kotatsu.core.util.ext.processLifecycleScope import org.koitharu.kotatsu.core.util.ext.requireValue import org.koitharu.kotatsu.history.domain.HistoryRepository import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.local.domain.DoubleMangaLoader import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.model.Manga -import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.util.runCatchingCancellable -import org.koitharu.kotatsu.reader.data.filterChapters import org.koitharu.kotatsu.reader.domain.ChaptersLoader import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings @@ -79,6 +79,7 @@ class ReaderViewModel @Inject constructor( private val pageLoader: PageLoader, private val chaptersLoader: ChaptersLoader, private val shortcutsUpdater: ShortcutsUpdater, + private val mangaLoader: DoubleMangaLoader, ) : BaseViewModel() { private val intent = MangaIntent(savedStateHandle) @@ -90,9 +91,9 @@ class ReaderViewModel @Inject constructor( private var bookmarkJob: Job? = null private var stateChangeJob: Job? = null private val currentState = MutableStateFlow(savedStateHandle[ReaderActivity.EXTRA_STATE]) - private val mangaData = MutableStateFlow(intent.manga) - private val chapters: LongSparseArray - get() = chaptersLoader.chapters + private val mangaData = MutableStateFlow(intent.manga?.let { DoubleManga(it) }) + private val mangaFlow: Flow + get() = mangaData.map { it?.any } val readerMode = MutableLiveData() val onPageSaved = SingleLiveEvent() @@ -100,7 +101,7 @@ class ReaderViewModel @Inject constructor( val uiState = MutableLiveData(null) val content = MutableLiveData(ReaderContent(emptyList(), null)) - val manga: Manga? + val manga: DoubleManga? get() = mangaData.value val readerAnimation = settings.observeAsLiveData( @@ -124,13 +125,13 @@ class ReaderViewModel @Inject constructor( val readerSettings = ReaderSettings( parentScope = viewModelScope, settings = settings, - colorFilterFlow = mangaData.flatMapLatest { + colorFilterFlow = mangaFlow.flatMapLatest { if (it == null) flowOf(null) else dataRepository.observeColorFilter(it.id) }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null), ) val isScreenshotsBlockEnabled = combine( - mangaData, + mangaFlow, settings.observeAsFlow(AppSettings.KEY_SCREENSHOTS_POLICY) { screenshotsPolicy }, ) { manga, policy -> policy == ScreenshotsPolicy.BLOCK_ALL || @@ -138,7 +139,7 @@ class ReaderViewModel @Inject constructor( }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) val isBookmarkAdded: LiveData = currentState.flatMapLatest { state -> - val manga = mangaData.value + val manga = mangaData.value?.any if (state == null || manga == null) { flowOf(false) } else { @@ -154,7 +155,7 @@ class ReaderViewModel @Inject constructor( if (key == AppSettings.KEY_READER_SLIDER) notifyStateChanged() }.launchIn(viewModelScope + Dispatchers.Default) launchJob(Dispatchers.Default) { - val mangaId = mangaData.filterNotNull().first().id + val mangaId = mangaFlow.filterNotNull().first().id shortcutsUpdater.notifyMangaOpened(mangaId) } } @@ -166,7 +167,7 @@ class ReaderViewModel @Inject constructor( fun switchMode(newMode: ReaderMode) { launchJob { - val manga = checkNotNull(mangaData.value) + val manga = checkNotNull(mangaData.value?.any) dataRepository.saveReaderMode( manga = manga, mode = newMode, @@ -189,7 +190,7 @@ class ReaderViewModel @Inject constructor( } val readerState = state ?: currentState.value ?: return historyRepository.saveStateAsync( - manga = mangaData.value ?: return, + manga = mangaData.value?.any ?: return, state = readerState, percent = computePercent(readerState.chapterId, readerState.page), ) @@ -242,7 +243,7 @@ class ReaderViewModel @Inject constructor( loadingJob = launchLoadingJob(Dispatchers.Default) { prevJob?.cancelAndJoin() content.postValue(ReaderContent(emptyList(), null)) - chaptersLoader.loadSingleChapter(mangaData.requireValue(), id) + chaptersLoader.loadSingleChapter(id) content.postValue(ReaderContent(chaptersLoader.snapshot(), ReaderState(id, page, 0))) } } @@ -285,7 +286,7 @@ class ReaderViewModel @Inject constructor( val state = checkNotNull(currentState.value) val page = checkNotNull(getCurrentPage()) { "Page not found" } val bookmark = Bookmark( - manga = checkNotNull(mangaData.value), + manga = checkNotNull(mangaData.value?.any), pageId = page.id, chapterId = state.chapterId, page = state.page, @@ -305,7 +306,7 @@ class ReaderViewModel @Inject constructor( } bookmarkJob = launchJob { loadingJob?.join() - val manga = checkNotNull(mangaData.value) + val manga = checkNotNull(mangaData.value?.any) val page = checkNotNull(getCurrentPage()) { "Page not found" } bookmarksRepository.removeBookmark(manga.id, page.id) onShowToast.call(R.string.bookmark_removed) @@ -314,32 +315,31 @@ class ReaderViewModel @Inject constructor( private fun loadImpl() { loadingJob = launchLoadingJob(Dispatchers.Default) { - var manga = dataRepository.resolveIntent(intent) ?: throw NotFoundException("Cannot find manga", "") + var manga = + DoubleManga(dataRepository.resolveIntent(intent) ?: throw NotFoundException("Cannot find manga", "")) mangaData.value = manga - val repo = mangaRepositoryFactory.create(manga.source) - manga = repo.getDetails(manga) - manga.chapters?.forEach { - chapters.put(it.id, it) - } + manga = mangaLoader.load(intent) + chaptersLoader.init(manga) // determine mode - val mode = detectReaderMode(manga, repo) + val singleManga = manga.requireAny() + val mode = detectReaderMode(singleManga) // obtain state if (currentState.value == null) { - currentState.value = historyRepository.getOne(manga)?.let { + currentState.value = historyRepository.getOne(singleManga)?.let { ReaderState(it) - } ?: ReaderState(manga, preselectedBranch) + } ?: ReaderState(singleManga, preselectedBranch) } - val branch = chapters[currentState.value?.chapterId ?: 0L]?.branch + val branch = chaptersLoader.peekChapter(currentState.value?.chapterId ?: 0L)?.branch mangaData.value = manga.filterChapters(branch) readerMode.emitValue(mode) - chaptersLoader.loadSingleChapter(manga, requireNotNull(currentState.value).chapterId) + chaptersLoader.loadSingleChapter(requireNotNull(currentState.value).chapterId) // save state if (!isIncognito) { currentState.value?.let { val percent = computePercent(it.chapterId, it.page) - historyRepository.addOrUpdate(manga, it.chapterId, it.page, it.scroll, percent) + historyRepository.addOrUpdate(singleManga, it.chapterId, it.page, it.scroll, percent) } } notifyStateChanged() @@ -367,15 +367,16 @@ class ReaderViewModel @Inject constructor( } } - private suspend fun detectReaderMode(manga: Manga, repo: MangaRepository): ReaderMode { + private suspend fun detectReaderMode(manga: Manga): ReaderMode { dataRepository.getReaderMode(manga.id)?.let { return it } val defaultMode = settings.defaultReaderMode if (!settings.isReaderModeDetectionEnabled || defaultMode == ReaderMode.WEBTOON) { return defaultMode } - val chapter = currentState.value?.chapterId?.let(chapters::get) + val chapter = currentState.value?.chapterId?.let { chaptersLoader.peekChapter(it) } ?: manga.chapters?.randomOrNull() ?: error("There are no chapters in this manga") + val repo = mangaRepositoryFactory.create(manga.source) val pages = repo.getPages(chapter) return runCatchingCancellable { val isWebtoon = dataRepository.determineMangaIsWebtoon(repo, pages) @@ -390,12 +391,12 @@ class ReaderViewModel @Inject constructor( @WorkerThread private fun notifyStateChanged() { val state = getCurrentState() - val chapter = state?.chapterId?.let(chapters::get) + val chapter = state?.chapterId?.let { chaptersLoader.peekChapter(it) } val newState = ReaderUiState( - mangaName = manga?.title, + mangaName = manga?.any?.title, chapterName = chapter?.name, chapterNumber = chapter?.number ?: 0, - chaptersTotal = manga?.getChapters(chapter?.branch)?.size ?: 0, + chaptersTotal = manga?.any?.getChapters(chapter?.branch)?.size ?: 0, totalPages = if (chapter != null) chaptersLoader.getPagesCount(chapter.id) else 0, currentPage = state?.page ?: 0, isSliderEnabled = settings.isReaderSliderEnabled, @@ -405,8 +406,8 @@ class ReaderViewModel @Inject constructor( } private fun computePercent(chapterId: Long, pageIndex: Int): Float { - val branch = chapters[chapterId]?.branch - val chapters = manga?.getChapters(branch) ?: return PROGRESS_NONE + val branch = chaptersLoader.peekChapter(chapterId)?.branch + val chapters = manga?.any?.getChapters(branch) ?: return PROGRESS_NONE val chaptersCount = chapters.size val chapterIndex = chapters.indexOfFirst { x -> x.id == chapterId } val pagesCount = chaptersLoader.getPagesCount(chapterId) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt index d83552079..714819f51 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt @@ -108,7 +108,7 @@ class ReaderConfigBottomSheet : R.id.button_color_filter -> { val page = viewModel.getCurrentPage() ?: return - val manga = viewModel.manga ?: return + val manga = viewModel.manga?.any ?: return startActivity(ColorFilterConfigActivity.newIntent(v.context, manga, page)) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt index bf9e86070..934245a5c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt @@ -12,8 +12,8 @@ import org.koitharu.kotatsu.core.util.ext.emitValue import org.koitharu.kotatsu.list.ui.model.ListHeader import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingFooter +import org.koitharu.kotatsu.local.domain.DoubleMangaLoader import org.koitharu.kotatsu.parsers.util.SuspendLazy -import org.koitharu.kotatsu.reader.data.filterChapters import org.koitharu.kotatsu.reader.domain.ChaptersLoader import javax.inject.Inject @@ -22,6 +22,7 @@ class PagesThumbnailsViewModel @Inject constructor( savedStateHandle: SavedStateHandle, mangaRepositoryFactory: MangaRepository.Factory, private val chaptersLoader: ChaptersLoader, + private val mangaLoader: DoubleMangaLoader, ) : BaseViewModel() { private val currentPageIndex: Int = savedStateHandle[PagesThumbnailsSheet.ARG_CURRENT_PAGE] ?: -1 @@ -30,13 +31,9 @@ class PagesThumbnailsViewModel @Inject constructor( private val repository = mangaRepositoryFactory.create(manga.source) private val mangaDetails = SuspendLazy { - repository.getDetails(manga).let { - chaptersLoader.chapters.clear() + mangaLoader.load(manga).let { val b = manga.chapters?.find { ch -> ch.id == initialChapterId }?.branch branch.emitValue(b) - it.getChapters(b)?.forEach { ch -> - chaptersLoader.chapters.put(ch.id, ch) - } it.filterChapters(b) } } @@ -50,7 +47,8 @@ class PagesThumbnailsViewModel @Inject constructor( init { loadingJob = launchJob(Dispatchers.Default) { - chaptersLoader.loadSingleChapter(mangaDetails.get(), initialChapterId) + chaptersLoader.init(mangaDetails.get()) + chaptersLoader.loadSingleChapter(initialChapterId) updateList() } } @@ -80,14 +78,14 @@ class PagesThumbnailsViewModel @Inject constructor( val mangaChapters = mangaDetails.tryGet().getOrNull()?.chapters.orEmpty() val hasPrevChapter = snapshot.firstOrNull()?.chapterId != mangaChapters.firstOrNull()?.id val hasNextChapter = snapshot.lastOrNull()?.chapterId != mangaChapters.lastOrNull()?.id - val pages = buildList(snapshot.size + chaptersLoader.chapters.size() + 2) { + val pages = buildList(snapshot.size + chaptersLoader.size + 2) { if (hasPrevChapter) { add(LoadingFooter(-1)) } var previousChapterId = 0L for (page in snapshot) { if (page.chapterId != previousChapterId) { - chaptersLoader.chapters[page.chapterId]?.let { + chaptersLoader.peekChapter(page.chapterId)?.let { add(ListHeader(it.name, 0, null)) } previousChapterId = page.chapterId diff --git a/app/src/main/res/raw/tags_redlist b/app/src/main/res/raw/tags_redlist index ecc5d9f11..537f2ecb8 100644 --- a/app/src/main/res/raw/tags_redlist +++ b/app/src/main/res/raw/tags_redlist @@ -18,3 +18,6 @@ scat тентакли футанари инцест +boys' love +girls' love +bdsm From 47f346b42c4cb0e51e0b676adc21cb1482805b1f Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 24 May 2023 14:27:04 +0300 Subject: [PATCH 07/94] Respect system DataSaver --- .../kotatsu/core/prefs/AppSettings.kt | 34 ++++++++++++++----- .../details/service/MangaPrefetchService.kt | 2 +- .../kotatsu/reader/domain/PageLoader.kt | 2 +- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt index fe2e24192..bf6cab962 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -2,7 +2,9 @@ package org.koitharu.kotatsu.core.prefs import android.content.Context import android.content.SharedPreferences +import android.net.ConnectivityManager import android.net.Uri +import android.os.Build import android.provider.Settings import androidx.annotation.FloatRange import androidx.appcompat.app.AppCompatDelegate @@ -179,10 +181,14 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { val isUnstableUpdatesAllowed: Boolean get() = prefs.getBoolean(KEY_UPDATES_UNSTABLE, false) - fun isContentPrefetchEnabled(): Boolean { - val policy = NetworkPolicy.from(prefs.getString(KEY_PREFETCH_CONTENT, null), NetworkPolicy.NEVER) - return policy.isNetworkAllowed(connectivityManager) - } + val isContentPrefetchEnabled: Boolean + get() { + if (isBackgroundNetworkRestricted()) { + return false + } + val policy = NetworkPolicy.from(prefs.getString(KEY_PREFETCH_CONTENT, null), NetworkPolicy.NEVER) + return policy.isNetworkAllowed(connectivityManager) + } var sourcesOrder: List get() = prefs.getString(KEY_SOURCES_ORDER, null) @@ -301,10 +307,14 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { get() = prefs.getFloat(KEY_READER_AUTOSCROLL_SPEED, 0f) set(@FloatRange(from = 0.0, to = 1.0) value) = prefs.edit { putFloat(KEY_READER_AUTOSCROLL_SPEED, value) } - fun isPagesPreloadEnabled(): Boolean { - val policy = NetworkPolicy.from(prefs.getString(KEY_PAGES_PRELOAD, null), NetworkPolicy.NON_METERED) - return policy.isNetworkAllowed(connectivityManager) - } + val isPagesPreloadEnabled: Boolean + get() { + if (isBackgroundNetworkRestricted()) { + return false + } + val policy = NetworkPolicy.from(prefs.getString(KEY_PAGES_PRELOAD, null), NetworkPolicy.NON_METERED) + return policy.isNetworkAllowed(connectivityManager) + } fun getMangaSources(includeHidden: Boolean): List { val list = remoteSources.toMutableList() @@ -342,6 +352,14 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { fun observe() = prefs.observe() + private fun isBackgroundNetworkRestricted(): Boolean { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + connectivityManager.restrictBackgroundStatus == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED + } else { + false + } + } + companion object { const val PAGE_SWITCH_TAPS = "taps" diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/service/MangaPrefetchService.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/service/MangaPrefetchService.kt index 4a549c6e7..189c3e00c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/service/MangaPrefetchService.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/service/MangaPrefetchService.kt @@ -116,7 +116,7 @@ class MangaPrefetchService : CoroutineIntentService() { return false } val entryPoint = EntryPointAccessors.fromApplication(context, PrefetchCompanionEntryPoint::class.java) - return entryPoint.contentCache.isCachingEnabled && entryPoint.settings.isContentPrefetchEnabled() + return entryPoint.contentCache.isCachingEnabled && entryPoint.settings.isContentPrefetchEnabled } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt index 1fef8621f..49701829a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt @@ -74,7 +74,7 @@ class PageLoader @Inject constructor( } fun isPrefetchApplicable(): Boolean { - return repository is RemoteMangaRepository && settings.isPagesPreloadEnabled() + return repository is RemoteMangaRepository && settings.isPagesPreloadEnabled } @AnyThread From 5a0c54e00ff26fc5a6eac00fb32fae49ca421c4d Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 27 May 2023 12:25:49 +0300 Subject: [PATCH 08/94] Replace LiveData with StateFlow --- .../kotatsu/core/os/ShortcutsUpdaterTest.kt | 4 +- .../settings/backup/AppBackupAgentTest.kt | 2 +- .../kotlin/org/koitharu/kotatsu/KotatsuApp.kt | 2 +- .../kotatsu/bookmarks/ui/BookmarksFragment.kt | 6 +- .../bookmarks/ui/BookmarksViewModel.kt | 17 ++- .../org/koitharu/kotatsu/core/AppModule.kt | 2 +- .../exceptions/resolve/DialogErrorObserver.kt | 5 +- .../core/exceptions/resolve/ErrorObserver.kt | 4 +- .../resolve/SnackbarErrorObserver.kt | 5 +- .../org/koitharu/kotatsu/core/model/Manga.kt | 4 + .../kotatsu/core/os/ShortcutsUpdater.kt | 2 +- .../core/parser/MangaDataRepository.kt | 70 --------- .../kotatsu/core/parser/MangaRepository.kt | 2 +- .../kotatsu/core/prefs/AppSettings.kt | 2 +- .../kotatsu/core/prefs/AppSettingsObserver.kt | 20 +-- .../koitharu/kotatsu/core/ui/BaseViewModel.kt | 29 ++-- .../core/ui/util/CountedBooleanLiveData.kt | 31 ---- .../core/ui/util/ReversibleActionObserver.kt | 9 +- .../org/koitharu/kotatsu/core/util/Event.kt | 36 +++++ .../kotatsu/core/util/FlowLiveData.kt | 86 ----------- .../kotatsu/core/util/SingleLiveEvent.kt | 50 ------- .../kotatsu/core/util/ext/EventFlow.kt | 18 +++ .../koitharu/kotatsu/core/util/ext/Flow.kt | 10 ++ .../kotatsu/core/util/ext/FlowObserver.kt | 35 +++++ .../kotatsu/core/util/ext/LiveData.kt | 32 ----- .../details/domain/DetailsInteractor.kt | 24 +--- .../domain/DoubleMangaLoadUseCase.kt} | 19 ++- .../domain}/model/DoubleManga.kt | 2 +- .../details/service/MangaPrefetchService.kt | 2 +- .../kotatsu/details/ui/ChaptersFragment.kt | 1 + .../kotatsu/details/ui/DetailsActivity.kt | 29 ++-- .../kotatsu/details/ui/DetailsFragment.kt | 6 +- .../kotatsu/details/ui/DetailsViewModel.kt | 107 +++++++------- .../scrobbling/ScrobblingInfoBottomSheet.kt | 10 +- .../kotatsu/download/domain/DownloadState.kt | 4 +- .../download/ui/list/DownloadsActivity.kt | 8 +- .../download/ui/list/DownloadsViewModel.kt | 22 +-- .../ui/worker/DownloadStartedObserver.kt | 6 +- .../download/ui/worker/DownloadWorker.kt | 4 +- .../explore/domain/ExploreRepository.kt | 2 +- .../kotatsu/explore/ui/ExploreFragment.kt | 8 +- .../kotatsu/explore/ui/ExploreViewModel.kt | 30 ++-- .../categories/FavouriteCategoriesActivity.kt | 4 +- .../FavouritesCategoriesViewModel.kt | 30 ++-- .../edit/FavouritesCategoryEditActivity.kt | 6 +- .../edit/FavouritesCategoryEditViewModel.kt | 33 ++--- .../select/FavouriteCategoriesBottomSheet.kt | 4 +- .../select/MangaCategoriesViewModel.kt | 6 +- .../ui/list/FavouritesListFragment.kt | 1 + .../ui/list/FavouritesListViewModel.kt | 25 ++-- .../{domain => data}/HistoryRepository.kt | 5 +- .../history/domain/HistoryUpdateUseCase.kt | 38 +++++ .../domain/{ => model}/MangaWithHistory.kt | 4 +- .../kotatsu/history/ui/HistoryListFragment.kt | 1 + .../history/ui/HistoryListViewModel.kt | 33 ++--- .../ui/util/ReadingProgressDrawable.kt | 2 +- .../history/ui/util/ReadingProgressView.kt | 2 +- .../kotatsu/list/ui/MangaListFragment.kt | 8 +- .../kotatsu/list/ui/MangaListViewModel.kt | 27 ++-- .../list/ui/adapter/MangaGridItemAD.kt | 2 +- .../ui/adapter/MangaListDetailedItemAD.kt | 2 +- .../list/ui/filter/FilterBottomSheet.kt | 1 + .../list/ui/filter/FilterCoordinator.kt | 15 +- .../list/ui/model/ListModelConversionExt.kt | 2 +- .../{domain => data}/LocalMangaRepository.kt | 7 +- .../data/importer/SingleMangaImporter.kt | 2 +- .../local/data/input/LocalMangaDirInput.kt | 2 +- .../local/data/input/LocalMangaInput.kt | 2 +- .../local/data/input/LocalMangaZipInput.kt | 2 +- .../local/domain/DeleteLocalMangaUseCase.kt | 42 ++++++ .../{data => domain/model}/LocalManga.kt | 6 +- .../local/ui/LocalChaptersRemoveService.kt | 4 +- .../kotatsu/local/ui/LocalListFragment.kt | 3 +- .../kotatsu/local/ui/LocalListViewModel.kt | 46 +++--- .../local/ui/LocalStorageCleanupWorker.kt | 2 +- .../koitharu/kotatsu/main/ui/MainActivity.kt | 6 +- .../koitharu/kotatsu/main/ui/MainViewModel.kt | 35 +++-- .../main/ui/protect/ProtectActivity.kt | 6 +- .../main/ui/protect/ProtectViewModel.kt | 5 +- .../kotatsu/reader/domain/ChaptersLoader.kt | 2 +- .../reader/domain/DetectReaderModeUseCase.kt | 97 +++++++++++++ .../kotatsu/reader/ui/PageSaveHelper.kt | 12 +- .../kotatsu/reader/ui/ReaderActivity.kt | 32 +++-- .../kotatsu/reader/ui/ReaderViewModel.kt | 136 ++++++------------ .../colorfilter/ColorFilterConfigActivity.kt | 4 +- .../ColorFilterConfigBackPressedDispatcher.kt | 1 + .../colorfilter/ColorFilterConfigViewModel.kt | 26 ++-- .../ui/config/ReaderConfigBottomSheet.kt | 8 +- .../reader/ui/pager/BaseReaderFragment.kt | 1 + .../pager/reversed/ReversedReaderFragment.kt | 1 + .../ui/pager/standard/PagerReaderFragment.kt | 1 + .../ui/pager/webtoon/WebtoonReaderFragment.kt | 1 + .../ui/thumbnails/PagesThumbnailsSheet.kt | 4 +- .../ui/thumbnails/PagesThumbnailsViewModel.kt | 17 ++- .../remotelist/ui/RemoteListViewModel.kt | 15 +- .../ui/config/ScrobblerConfigActivity.kt | 4 +- .../ui/config/ScrobblerConfigViewModel.kt | 25 ++-- .../selector/ScrobblingSelectorBottomSheet.kt | 6 +- .../selector/ScrobblingSelectorViewModel.kt | 29 ++-- .../kotatsu/search/ui/SearchActivity.kt | 1 + .../kotatsu/search/ui/SearchViewModel.kt | 8 +- .../search/ui/multi/MultiSearchActivity.kt | 14 +- .../search/ui/multi/MultiSearchViewModel.kt | 25 ++-- .../ui/suggestion/SearchSuggestionFragment.kt | 1 + .../suggestion/SearchSuggestionViewModel.kt | 12 +- .../settings/about/AboutSettingsFragment.kt | 4 +- .../settings/about/AboutSettingsViewModel.kt | 5 +- .../settings/backup/BackupDialogFragment.kt | 6 +- .../settings/backup/BackupViewModel.kt | 9 +- .../settings/backup/RestoreDialogFragment.kt | 6 +- .../settings/backup/RestoreViewModel.kt | 9 +- .../newsources/NewSourcesDialogFragment.kt | 1 + .../newsources/NewSourcesViewModel.kt | 19 ++- .../settings/onboard/OnboardDialogFragment.kt | 1 + .../settings/onboard/OnboardViewModel.kt | 4 +- .../settings/protect/ProtectSetupActivity.kt | 1 + .../settings/protect/ProtectSetupViewModel.kt | 16 ++- .../settings/sources/SourcesListFragment.kt | 4 +- .../settings/sources/SourcesListViewModel.kt | 47 +++--- .../kotatsu/settings/tools/ToolsFragment.kt | 1 + .../kotatsu/settings/tools/ToolsViewModel.kt | 23 ++- .../tracker/TrackerSettingsFragment.kt | 1 + .../tracker/TrackerSettingsViewModel.kt | 7 +- .../TrackerCategoriesConfigSheet.kt | 1 + .../TrackerCategoriesConfigViewModel.kt | 6 +- ...itory.kt => ShelfContentObserveUseCase.kt} | 34 +---- .../shelf/domain/{ => model}/ShelfContent.kt | 4 +- .../shelf/domain/{ => model}/ShelfSection.kt | 2 +- .../kotatsu/shelf/ui/ShelfFragment.kt | 8 +- .../kotatsu/shelf/ui/ShelfViewModel.kt | 49 ++++--- .../shelf/ui/config/ShelfSettingsActivity.kt | 3 +- .../config/ShelfSettingsAdapterDelegates.kt | 2 +- .../shelf/ui/config/ShelfSettingsItemModel.kt | 10 +- .../shelf/ui/config/ShelfSettingsViewModel.kt | 10 +- .../suggestions/ui/SuggestionsViewModel.kt | 11 +- .../suggestions/ui/SuggestionsWorker.kt | 2 +- .../kotatsu/sync/ui/SyncAuthActivity.kt | 6 +- .../kotatsu/sync/ui/SyncAuthViewModel.kt | 17 +-- .../kotatsu/tracker/domain/Tracker.kt | 6 +- .../kotatsu/tracker/ui/feed/FeedFragment.kt | 6 +- .../kotatsu/tracker/ui/feed/FeedViewModel.kt | 13 +- .../tracker/ui/updates/UpdatesViewModel.kt | 12 +- .../kotatsu/tracker/work/TrackWorker.kt | 15 +- .../widget/recent/RecentListFactory.kt | 2 +- .../widget/recent/RecentWidgetService.kt | 2 +- .../widget/shelf/ShelfConfigActivity.kt | 4 +- .../widget/shelf/ShelfConfigViewModel.kt | 16 ++- 147 files changed, 1042 insertions(+), 1034 deletions(-) delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/CountedBooleanLiveData.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/util/Event.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/util/FlowLiveData.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/util/SingleLiveEvent.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/EventFlow.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/FlowObserver.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/LiveData.kt rename app/src/main/kotlin/org/koitharu/kotatsu/{local/domain/DoubleMangaLoader.kt => details/domain/DoubleMangaLoadUseCase.kt} (79%) rename app/src/main/kotlin/org/koitharu/kotatsu/{core => details/domain}/model/DoubleManga.kt (97%) rename app/src/main/kotlin/org/koitharu/kotatsu/history/{domain => data}/HistoryRepository.kt (96%) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryUpdateUseCase.kt rename app/src/main/kotlin/org/koitharu/kotatsu/history/domain/{ => model}/MangaWithHistory.kt (77%) rename app/src/main/kotlin/org/koitharu/kotatsu/local/{domain => data}/LocalMangaRepository.kt (95%) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/local/domain/DeleteLocalMangaUseCase.kt rename app/src/main/kotlin/org/koitharu/kotatsu/local/{data => domain/model}/LocalManga.kt (92%) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/DetectReaderModeUseCase.kt rename app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/{ShelfRepository.kt => ShelfContentObserveUseCase.kt} (74%) rename app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/{ => model}/ShelfContent.kt (89%) rename app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/{ => model}/ShelfSection.kt (62%) diff --git a/app/src/androidTest/java/org/koitharu/kotatsu/core/os/ShortcutsUpdaterTest.kt b/app/src/androidTest/java/org/koitharu/kotatsu/core/os/ShortcutsUpdaterTest.kt index 4b1784bed..6b9de214f 100644 --- a/app/src/androidTest/java/org/koitharu/kotatsu/core/os/ShortcutsUpdaterTest.kt +++ b/app/src/androidTest/java/org/koitharu/kotatsu/core/os/ShortcutsUpdaterTest.kt @@ -8,7 +8,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest -import javax.inject.Inject import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue @@ -19,7 +18,8 @@ import org.junit.runner.RunWith import org.koitharu.kotatsu.SampleData import org.koitharu.kotatsu.awaitForIdle import org.koitharu.kotatsu.core.db.MangaDatabase -import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.history.data.HistoryRepository +import javax.inject.Inject @HiltAndroidTest @RunWith(AndroidJUnit4::class) diff --git a/app/src/androidTest/java/org/koitharu/kotatsu/settings/backup/AppBackupAgentTest.kt b/app/src/androidTest/java/org/koitharu/kotatsu/settings/backup/AppBackupAgentTest.kt index f885ddb36..9984821cc 100644 --- a/app/src/androidTest/java/org/koitharu/kotatsu/settings/backup/AppBackupAgentTest.kt +++ b/app/src/androidTest/java/org/koitharu/kotatsu/settings/backup/AppBackupAgentTest.kt @@ -17,7 +17,7 @@ import org.koitharu.kotatsu.core.backup.BackupRepository import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.entity.toMangaTags import org.koitharu.kotatsu.favourites.domain.FavouritesRepository -import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.history.data.HistoryRepository import java.io.File import javax.inject.Inject diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/KotatsuApp.kt b/app/src/main/kotlin/org/koitharu/kotatsu/KotatsuApp.kt index b8a5ac19d..164095e81 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/KotatsuApp.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/KotatsuApp.kt @@ -22,8 +22,8 @@ import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.WorkServiceStopHelper import org.koitharu.kotatsu.core.util.ext.processLifecycleScope +import org.koitharu.kotatsu.local.data.LocalMangaRepository import org.koitharu.kotatsu.local.data.PagesCache -import org.koitharu.kotatsu.local.domain.LocalMangaRepository import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.reader.domain.PageLoader import javax.inject.Inject diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksFragment.kt index e76ee3ed0..f2db6cb49 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksFragment.kt @@ -30,6 +30,8 @@ import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller import org.koitharu.kotatsu.core.ui.util.ReversibleAction import org.koitharu.kotatsu.core.ui.util.reverseAsync import org.koitharu.kotatsu.core.util.ext.invalidateNestedItemDecorations +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.databinding.FragmentListSimpleBinding import org.koitharu.kotatsu.details.ui.DetailsActivity @@ -81,8 +83,8 @@ class BookmarksFragment : binding.recyclerView.addItemDecoration(spacingDecoration) viewModel.content.observe(viewLifecycleOwner, ::onListChanged) - viewModel.onError.observe(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) - viewModel.onActionDone.observe(viewLifecycleOwner, ::onActionDone) + viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) + viewModel.onActionDone.observeEvent(viewLifecycleOwner, ::onActionDone) } override fun onDestroyView() { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksViewModel.kt index 614691d49..d08ce07b4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksViewModel.kt @@ -1,18 +1,21 @@ package org.koitharu.kotatsu.bookmarks.ui -import androidx.lifecycle.LiveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.util.ReversibleAction -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingState @@ -25,9 +28,9 @@ class BookmarksViewModel @Inject constructor( private val repository: BookmarksRepository, ) : BaseViewModel() { - val onActionDone = SingleLiveEvent() + val onActionDone = MutableEventFlow() - val content: LiveData> = repository.observeBookmarks() + val content: StateFlow> = repository.observeBookmarks() .map { list -> if (list.isEmpty()) { listOf( @@ -43,12 +46,12 @@ class BookmarksViewModel @Inject constructor( } } .catch { e -> emit(listOf(e.toErrorState(canRetry = false))) } - .asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) fun removeBookmarks(ids: Map>) { launchJob(Dispatchers.Default) { val handle = repository.removeBookmarks(ids) - onActionDone.emitCall(ReversibleAction(R.string.bookmarks_removed, handle)) + onActionDone.call(ReversibleAction(R.string.bookmarks_removed, handle)) } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt index cbf361112..39b9b701b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt @@ -42,9 +42,9 @@ import org.koitharu.kotatsu.core.util.ext.connectivityManager import org.koitharu.kotatsu.core.util.ext.isLowRamDevice import org.koitharu.kotatsu.local.data.CacheDir import org.koitharu.kotatsu.local.data.CbzFetcher -import org.koitharu.kotatsu.local.data.LocalManga import org.koitharu.kotatsu.local.data.LocalStorageChanges import org.koitharu.kotatsu.local.data.PagesCache +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.main.ui.protect.AppProtectHelper import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.reader.ui.thumbnails.MangaPageFetcher diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt index 68949cc36..1edf3b662 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt @@ -22,10 +22,7 @@ class DialogErrorObserver( fragment: Fragment?, ) : this(host, fragment, null, null) - override fun onChanged(value: Throwable?) { - if (value == null) { - return - } + override suspend fun emit(value: Throwable) { val listener = DialogListener(value) val dialogBuilder = MaterialAlertDialogBuilder(activity ?: host.context) .setMessage(value.getDisplayMessage(host.context.resources)) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ErrorObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ErrorObserver.kt index 3af75685e..a64fb9edf 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ErrorObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ErrorObserver.kt @@ -7,8 +7,8 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.lifecycle.LifecycleCoroutineScope import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.Observer import androidx.lifecycle.coroutineScope +import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import org.koitharu.kotatsu.core.util.ext.findActivity @@ -19,7 +19,7 @@ abstract class ErrorObserver( protected val fragment: Fragment?, private val resolver: ExceptionResolver?, private val onResolved: Consumer?, -) : Observer { +) : FlowCollector { protected val activity = host.context.findActivity() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt index 9a1ef14d5..e39897cfc 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt @@ -22,10 +22,7 @@ class SnackbarErrorObserver( fragment: Fragment?, ) : this(host, fragment, null, null) - override fun onChanged(value: Throwable?) { - if (value == null) { - return - } + override suspend fun emit(value: Throwable) { val snackbar = Snackbar.make(host, value.getDisplayMessage(host.context.resources), Snackbar.LENGTH_SHORT) if (activity is BottomNavOwner) { snackbar.anchorView = activity.bottomNav diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/Manga.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/Manga.kt index cbfc5e1f8..ce0b3e7f1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/Manga.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/Manga.kt @@ -24,6 +24,10 @@ fun Collection.countChaptersByBranch(): Int { return acc.values.max() } +fun Manga.findChapter(id: Long): MangaChapter? { + return chapters?.find { it.id == id } +} + fun Manga.getPreferredBranch(history: MangaHistory?): String? { val ch = chapters if (ch.isNullOrEmpty()) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/os/ShortcutsUpdater.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/os/ShortcutsUpdater.kt index 43c904696..4481c4038 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/os/ShortcutsUpdater.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/os/ShortcutsUpdater.kt @@ -27,7 +27,7 @@ import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.ext.getDrawableOrThrow import org.koitharu.kotatsu.core.util.ext.processLifecycleScope -import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.reader.ui.ReaderActivity diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaDataRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaDataRepository.kt index 393f5357f..45c2e5df9 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaDataRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaDataRepository.kt @@ -1,37 +1,24 @@ package org.koitharu.kotatsu.core.parser -import android.graphics.BitmapFactory -import android.net.Uri -import android.util.Size import androidx.room.withTransaction import dagger.Reusable -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map -import kotlinx.coroutines.runInterruptible import okhttp3.OkHttpClient -import okhttp3.Request import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.entity.MangaPrefsEntity import org.koitharu.kotatsu.core.db.entity.toEntities import org.koitharu.kotatsu.core.db.entity.toEntity import org.koitharu.kotatsu.core.db.entity.toManga import org.koitharu.kotatsu.core.db.entity.toMangaTags -import org.koitharu.kotatsu.core.network.CommonHeaders import org.koitharu.kotatsu.core.network.MangaHttpClient import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.parsers.model.Manga -import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaTag -import org.koitharu.kotatsu.parsers.util.await import org.koitharu.kotatsu.reader.domain.ReaderColorFilter -import java.io.File -import java.io.InputStream -import java.util.zip.ZipFile import javax.inject.Inject -import kotlin.math.roundToInt @Reusable class MangaDataRepository @Inject constructor( @@ -104,67 +91,10 @@ class MangaDataRepository @Inject constructor( } } - /** - * Automatic determine type of manga by page size - * @return ReaderMode.WEBTOON if page is wide - */ - suspend fun determineMangaIsWebtoon(repository: MangaRepository, pages: List): Boolean { - val pageIndex = (pages.size * 0.3).roundToInt() - val page = requireNotNull(pages.getOrNull(pageIndex)) { "No pages" } - val url = repository.getPageUrl(page) - val uri = Uri.parse(url) - val size = if (uri.scheme == "cbz") { - runInterruptible(Dispatchers.IO) { - val zip = ZipFile(uri.schemeSpecificPart) - val entry = zip.getEntry(uri.fragment) - zip.getInputStream(entry).use { - getBitmapSize(it) - } - } - } else { - val request = Request.Builder() - .url(url) - .get() - .tag(MangaSource::class.java, page.source) - .cacheControl(CommonHeaders.CACHE_CONTROL_NO_STORE) - .build() - okHttpClient.newCall(request).await().use { - runInterruptible(Dispatchers.IO) { - getBitmapSize(it.body?.byteStream()) - } - } - } - return size.width * MIN_WEBTOON_RATIO < size.height - } - private fun newEntity(mangaId: Long) = MangaPrefsEntity( mangaId = mangaId, mode = -1, cfBrightness = 0f, cfContrast = 0f, ) - - companion object { - - private const val MIN_WEBTOON_RATIO = 2 - - suspend fun getImageMimeType(file: File): String? = runInterruptible(Dispatchers.IO) { - val options = BitmapFactory.Options().apply { - inJustDecodeBounds = true - } - BitmapFactory.decodeFile(file.path, options)?.recycle() - options.outMimeType - } - - private fun getBitmapSize(input: InputStream?): Size { - val options = BitmapFactory.Options().apply { - inJustDecodeBounds = true - } - BitmapFactory.decodeStream(input, null, options)?.recycle() - val imageHeight: Int = options.outHeight - val imageWidth: Int = options.outWidth - check(imageHeight > 0 && imageWidth > 0) - return Size(imageWidth, imageHeight) - } - } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaRepository.kt index b90b10b52..36bbbc0c7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaRepository.kt @@ -2,7 +2,7 @@ package org.koitharu.kotatsu.core.parser import androidx.annotation.AnyThread import org.koitharu.kotatsu.core.cache.ContentCache -import org.koitharu.kotatsu.local.domain.LocalMangaRepository +import org.koitharu.kotatsu.local.data.LocalMangaRepository import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt index bf6cab962..09c883755 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -25,7 +25,7 @@ import org.koitharu.kotatsu.core.util.ext.toUriOrNull import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.util.mapToSet -import org.koitharu.kotatsu.shelf.domain.ShelfSection +import org.koitharu.kotatsu.shelf.domain.model.ShelfSection import java.io.File import java.net.Proxy import java.util.Collections diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettingsObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettingsObserver.kt index 606ae9d84..ed6d14f68 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettingsObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettingsObserver.kt @@ -1,13 +1,11 @@ package org.koitharu.kotatsu.core.prefs -import androidx.lifecycle.liveData import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transform -import kotlin.coroutines.CoroutineContext fun AppSettings.observeAsFlow(key: String, valueProducer: AppSettings.() -> T) = flow { var lastValue: T = valueProducer() @@ -23,25 +21,9 @@ fun AppSettings.observeAsFlow(key: String, valueProducer: AppSettings.() -> } } -fun AppSettings.observeAsLiveData( - context: CoroutineContext, - key: String, - valueProducer: AppSettings.() -> T, -) = liveData(context) { - emit(valueProducer()) - observe().collect { - if (it == key) { - val value = valueProducer() - if (value != latestValue) { - emit(value) - } - } - } -} - fun AppSettings.observeAsStateFlow( - key: String, scope: CoroutineScope, + key: String, valueProducer: AppSettings.() -> T, ): StateFlow = observe().transform { if (it == key) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseViewModel.kt index 12cda4167..74948fcdb 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseViewModel.kt @@ -1,6 +1,5 @@ package org.koitharu.kotatsu.core.ui -import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.CancellationException @@ -8,9 +7,16 @@ import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.koitharu.kotatsu.core.ui.util.CountedBooleanLiveData -import org.koitharu.kotatsu.core.util.SingleLiveEvent +import org.koitharu.kotatsu.core.util.ext.EventFlow +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.util.ext.printStackTraceDebug import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext @@ -18,16 +24,17 @@ import kotlin.coroutines.EmptyCoroutineContext abstract class BaseViewModel : ViewModel() { @JvmField - protected val loadingCounter = CountedBooleanLiveData() + protected val loadingCounter = MutableStateFlow(0) @JvmField - protected val errorEvent = SingleLiveEvent() + protected val errorEvent = MutableEventFlow() - val onError: LiveData + val onError: EventFlow get() = errorEvent - val isLoading: LiveData - get() = loadingCounter + val isLoading: StateFlow + get() = loadingCounter.map { it > 0 } + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false) protected fun launchJob( context: CoroutineContext = EmptyCoroutineContext, @@ -51,7 +58,11 @@ abstract class BaseViewModel : ViewModel() { private fun createErrorHandler() = CoroutineExceptionHandler { _, throwable -> throwable.printStackTraceDebug() if (throwable !is CancellationException) { - errorEvent.postCall(throwable) + errorEvent.call(throwable) } } + + protected fun MutableStateFlow.increment() = update { it + 1 } + + protected fun MutableStateFlow.decrement() = update { it - 1 } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/CountedBooleanLiveData.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/CountedBooleanLiveData.kt deleted file mode 100644 index a737c0af9..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/CountedBooleanLiveData.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.koitharu.kotatsu.core.ui.util - -import androidx.annotation.AnyThread -import androidx.lifecycle.LiveData -import java.util.concurrent.atomic.AtomicInteger - -class CountedBooleanLiveData : LiveData(false) { - - private val counter = AtomicInteger(0) - - @AnyThread - fun increment() { - if (counter.getAndIncrement() == 0) { - postValue(true) - } - } - - @AnyThread - fun decrement() { - if (counter.decrementAndGet() == 0) { - postValue(false) - } - } - - @AnyThread - fun reset() { - if (counter.getAndSet(0) != 0) { - postValue(false) - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/ReversibleActionObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/ReversibleActionObserver.kt index 4f6319f66..b66e64cbb 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/ReversibleActionObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/ReversibleActionObserver.kt @@ -1,18 +1,15 @@ package org.koitharu.kotatsu.core.ui.util import android.view.View -import androidx.lifecycle.Observer import com.google.android.material.snackbar.Snackbar +import kotlinx.coroutines.flow.FlowCollector import org.koitharu.kotatsu.R class ReversibleActionObserver( private val snackbarHost: View, -) : Observer { +) : FlowCollector { - override fun onChanged(value: ReversibleAction?) { - if (value == null) { - return - } + override suspend fun emit(value: ReversibleAction) { val handle = value.handle val length = if (handle == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG val snackbar = Snackbar.make(snackbarHost, value.stringResId, length) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/Event.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/Event.kt new file mode 100644 index 000000000..e14d2703c --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/Event.kt @@ -0,0 +1,36 @@ +package org.koitharu.kotatsu.core.util + +import kotlinx.coroutines.flow.FlowCollector + +class Event( + private val data: T, +) { + private var isConsumed = false + + suspend fun consume(collector: FlowCollector) { + if (isConsumed) { + collector.emit(data) + isConsumed = true + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Event<*> + + if (data != other.data) return false + return isConsumed == other.isConsumed + } + + override fun hashCode(): Int { + var result = data?.hashCode() ?: 0 + result = 31 * result + isConsumed.hashCode() + return result + } + + override fun toString(): String { + return "Event(data=$data, isConsumed=$isConsumed)" + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/FlowLiveData.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/FlowLiveData.kt deleted file mode 100644 index 7b3693902..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/FlowLiveData.kt +++ /dev/null @@ -1,86 +0,0 @@ -package org.koitharu.kotatsu.core.util - -import androidx.lifecycle.LiveData -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext - -private const val DEFAULT_TIMEOUT = 5_000L - -/** - * Similar to a CoroutineLiveData but optimized for using within infinite flows - */ -class FlowLiveData( - private val flow: Flow, - defaultValue: T, - context: CoroutineContext = EmptyCoroutineContext, - private val timeoutInMs: Long = DEFAULT_TIMEOUT, -) : LiveData(defaultValue) { - - private val scope = CoroutineScope(Dispatchers.Main.immediate + context + SupervisorJob(context[Job])) - private var job: Job? = null - private var cancellationJob: Job? = null - - override fun onActive() { - super.onActive() - cancellationJob?.cancel() - cancellationJob = null - if (job?.isActive == true) { - return - } - job = scope.launch { - flow.collect(Collector()) - } - } - - override fun onInactive() { - super.onInactive() - cancellationJob?.cancel() - cancellationJob = scope.launch(Dispatchers.Main.immediate) { - delay(timeoutInMs) - if (!hasActiveObservers()) { - job?.cancel() - job = null - } - } - } - - private inner class Collector : FlowCollector { - - private var previousValue: Any? = value - private val dispatcher = Dispatchers.Main.immediate - - override suspend fun emit(value: T) { - if (previousValue != value) { - previousValue = value - if (dispatcher.isDispatchNeeded(EmptyCoroutineContext)) { - withContext(dispatcher) { - setValue(value) - } - } else { - setValue(value) - } - } - } - } -} - -fun Flow.asFlowLiveData( - context: CoroutineContext = EmptyCoroutineContext, - defaultValue: T, - timeoutInMs: Long = DEFAULT_TIMEOUT, -): LiveData = FlowLiveData(this, defaultValue, context, timeoutInMs) - -fun StateFlow.asFlowLiveData( - context: CoroutineContext = EmptyCoroutineContext, - timeoutInMs: Long = DEFAULT_TIMEOUT, -): LiveData = FlowLiveData(this, value, context, timeoutInMs) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/SingleLiveEvent.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/SingleLiveEvent.kt deleted file mode 100644 index 504690d6f..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/SingleLiveEvent.kt +++ /dev/null @@ -1,50 +0,0 @@ -package org.koitharu.kotatsu.core.util - -import androidx.annotation.AnyThread -import androidx.annotation.MainThread -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LiveData -import androidx.lifecycle.Observer -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.coroutines.EmptyCoroutineContext - -class SingleLiveEvent : LiveData() { - - private val pending = AtomicBoolean(false) - - override fun observe(owner: LifecycleOwner, observer: Observer) { - super.observe(owner) { - if (pending.compareAndSet(true, false)) { - observer.onChanged(it) - } - } - } - - override fun setValue(value: T) { - pending.set(true) - super.setValue(value) - } - - @MainThread - fun call(newValue: T) { - setValue(newValue) - } - - @AnyThread - fun postCall(newValue: T) { - postValue(newValue) - } - - suspend fun emitCall(newValue: T) { - val dispatcher = Dispatchers.Main.immediate - if (dispatcher.isDispatchNeeded(EmptyCoroutineContext)) { - withContext(dispatcher) { - setValue(newValue) - } - } else { - setValue(newValue) - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/EventFlow.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/EventFlow.kt new file mode 100644 index 000000000..11fc25beb --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/EventFlow.kt @@ -0,0 +1,18 @@ +package org.koitharu.kotatsu.core.util.ext + +import androidx.annotation.AnyThread +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import org.koitharu.kotatsu.core.util.Event + +@Suppress("FunctionName") +fun MutableEventFlow() = MutableStateFlow?>(null) + +typealias EventFlow = StateFlow?> + +typealias MutableEventFlow = MutableStateFlow?> + +@AnyThread +fun MutableEventFlow.call(data: T) { + value = Event(data) +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Flow.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Flow.kt index 3db3bb15e..2aa0c1e62 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Flow.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Flow.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.transformLatest +import org.koitharu.kotatsu.R fun Flow.onFirst(action: suspend (T) -> Unit): Flow { var isFirstCall = true @@ -52,3 +53,12 @@ fun Flow>.flatten(): Flow = flow { } } } + +fun Flow.zipWithPrevious(): Flow> = flow { + var previous: T? = null + collect { value -> + val result = previous to value + previous = value + emit(result) + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/FlowObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/FlowObserver.kt new file mode 100644 index 000000000..bfd2db25f --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/FlowObserver.kt @@ -0,0 +1,35 @@ +package org.koitharu.kotatsu.core.util.ext + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import org.koitharu.kotatsu.BuildConfig +import org.koitharu.kotatsu.core.util.Event + +fun Flow.observe(owner: LifecycleOwner, collector: FlowCollector) { + if (BuildConfig.DEBUG) { + require((this as? StateFlow)?.value !is Event<*>) + } + val start = if (this is StateFlow) CoroutineStart.UNDISPATCHED else CoroutineStart.DEFAULT + owner.lifecycleScope.launch(start = start) { + owner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + collect(collector) + } + } +} + +fun Flow?>.observeEvent(owner: LifecycleOwner, collector: FlowCollector) { + owner.lifecycleScope.launch { + owner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + collect { + it?.consume(collector) + } + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/LiveData.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/LiveData.kt deleted file mode 100644 index ed8d96b62..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/LiveData.kt +++ /dev/null @@ -1,32 +0,0 @@ -package org.koitharu.kotatsu.core.util.ext - -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.koitharu.kotatsu.core.util.BufferedObserver -import kotlin.coroutines.EmptyCoroutineContext - -fun LiveData.requireValue(): T = checkNotNull(value) { - "LiveData value is null" -} - -fun LiveData.observeWithPrevious(owner: LifecycleOwner, observer: BufferedObserver) { - var previous: T? = null - this.observe(owner) { - observer.onChanged(it, previous) - previous = it - } -} - -suspend fun MutableLiveData.emitValue(newValue: T) { - val dispatcher = Dispatchers.Main.immediate - if (dispatcher.isDispatchNeeded(EmptyCoroutineContext)) { - withContext(dispatcher) { - value = newValue - } - } else { - value = newValue - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt index 3968e4399..350c66772 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt @@ -6,23 +6,21 @@ import kotlinx.coroutines.flow.distinctUntilChangedBy import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map -import org.koitharu.kotatsu.core.model.DoubleManga -import org.koitharu.kotatsu.core.model.isLocal import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.observeAsFlow +import org.koitharu.kotatsu.details.domain.model.DoubleManga import org.koitharu.kotatsu.favourites.domain.FavouritesRepository -import org.koitharu.kotatsu.history.domain.HistoryRepository -import org.koitharu.kotatsu.local.data.LocalManga -import org.koitharu.kotatsu.local.domain.LocalMangaRepository +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.local.data.LocalMangaRepository +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo import org.koitharu.kotatsu.tracker.domain.TrackingRepository -import org.koitharu.kotatsu.util.ext.printStackTraceDebug -import java.io.IOException import javax.inject.Inject +@Deprecated("") class DetailsInteractor @Inject constructor( private val historyRepository: HistoryRepository, private val favouritesRepository: FavouritesRepository, @@ -56,18 +54,6 @@ class DetailsInteractor @Inject constructor( } } - suspend fun deleteLocalManga(manga: Manga) { - val victim = if (manga.isLocal) manga else localMangaRepository.findSavedManga(manga)?.manga - checkNotNull(victim) { "Cannot find saved manga for ${manga.title}" } - val original = if (manga.isLocal) localMangaRepository.getRemoteManga(manga) else manga - localMangaRepository.delete(victim) || throw IOException("Unable to delete file") - runCatchingCancellable { - historyRepository.deleteOrSwap(victim, original) - }.onFailure { - it.printStackTraceDebug() - } - } - fun observeIncognitoMode(mangaFlow: Flow): Flow { return mangaFlow .distinctUntilChangedBy { it?.isNsfw } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/DoubleMangaLoader.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DoubleMangaLoadUseCase.kt similarity index 79% rename from app/src/main/kotlin/org/koitharu/kotatsu/local/domain/DoubleMangaLoader.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DoubleMangaLoadUseCase.kt index 5cf8325c1..143d1ae24 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/DoubleMangaLoader.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DoubleMangaLoadUseCase.kt @@ -1,27 +1,26 @@ -package org.koitharu.kotatsu.local.domain +package org.koitharu.kotatsu.details.domain -import dagger.Reusable import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope -import org.koitharu.kotatsu.core.model.DoubleManga import org.koitharu.kotatsu.core.model.isLocal import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.parser.MangaIntent import org.koitharu.kotatsu.core.parser.MangaRepository +import org.koitharu.kotatsu.details.domain.model.DoubleManga +import org.koitharu.kotatsu.local.data.LocalMangaRepository import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import javax.inject.Inject -@Reusable -class DoubleMangaLoader @Inject constructor( +class DoubleMangaLoadUseCase @Inject constructor( private val mangaDataRepository: MangaDataRepository, private val localMangaRepository: LocalMangaRepository, private val mangaRepositoryFactory: MangaRepository.Factory, ) { - suspend fun load(manga: Manga): DoubleManga = coroutineScope { + suspend operator fun invoke(manga: Manga): DoubleManga = coroutineScope { val remoteDeferred = async(Dispatchers.Default) { loadRemote(manga) } val localDeferred = async(Dispatchers.Default) { loadLocal(manga) } DoubleManga( @@ -30,14 +29,14 @@ class DoubleMangaLoader @Inject constructor( ) } - suspend fun load(mangaId: Long): DoubleManga { + suspend operator fun invoke(mangaId: Long): DoubleManga { val manga = mangaDataRepository.findMangaById(mangaId) ?: throwNFE() - return load(manga) + return invoke(manga) } - suspend fun load(intent: MangaIntent): DoubleManga { + suspend operator fun invoke(intent: MangaIntent): DoubleManga { val manga = mangaDataRepository.resolveIntent(intent) ?: throwNFE() - return load(manga) + return invoke(manga) } private suspend fun loadLocal(manga: Manga): Result? { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/DoubleManga.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/model/DoubleManga.kt similarity index 97% rename from app/src/main/kotlin/org/koitharu/kotatsu/core/model/DoubleManga.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/details/domain/model/DoubleManga.kt index 460286fa1..732f59902 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/DoubleManga.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/model/DoubleManga.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.core.model +package org.koitharu.kotatsu.details.domain.model import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/service/MangaPrefetchService.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/service/MangaPrefetchService.kt index 189c3e00c..ad889e3ce 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/service/MangaPrefetchService.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/service/MangaPrefetchService.kt @@ -10,7 +10,7 @@ import org.koitharu.kotatsu.core.model.parcelable.ParcelableMangaChapters import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.ui.CoroutineIntentService import org.koitharu.kotatsu.core.util.ext.getParcelableExtraCompat -import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaSource diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt index e3b3c1e64..07a6f8902 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt @@ -16,6 +16,7 @@ import org.koitharu.kotatsu.core.ui.BaseFragment import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.util.RecyclerViewScrollCallback +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.databinding.FragmentChaptersBinding import org.koitharu.kotatsu.details.ui.adapter.ChaptersAdapter diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index f090a47fa..64abbc9f8 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -18,10 +18,11 @@ import androidx.core.graphics.Insets import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.core.view.updatePadding -import androidx.lifecycle.Observer import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.filterNotNull import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga @@ -32,6 +33,8 @@ import org.koitharu.kotatsu.core.ui.dialog.RecyclerViewAlertDialog import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.ui.widgets.BottomSheetHeaderBar import org.koitharu.kotatsu.core.util.ViewBadge +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.setNavigationBarTransparentCompat import org.koitharu.kotatsu.core.util.ext.textAndVisible import org.koitharu.kotatsu.databinding.ActivityDetailsBinding @@ -90,10 +93,10 @@ class DetailsActivity : ChaptersMenuProvider(viewModel, null) } - viewModel.manga.observe(this, ::onMangaUpdated) + viewModel.manga.filterNotNull().observe(this, ::onMangaUpdated) viewModel.newChaptersCount.observe(this, ::onNewChaptersChanged) - viewModel.onMangaRemoved.observe(this, ::onMangaRemoved) - viewModel.onError.observe( + viewModel.onMangaRemoved.observeEvent(this, ::onMangaRemoved) + viewModel.onError.observeEvent( this, SnackbarErrorObserver( host = viewBinding.containerDetails, @@ -106,11 +109,11 @@ class DetailsActivity : }, ), ) - viewModel.onShowToast.observe(this) { + viewModel.onShowToast.observeEvent(this) { makeSnackbar(getString(it), Snackbar.LENGTH_SHORT).show() } viewModel.historyInfo.observe(this, ::onHistoryChanged) - viewModel.selectedBranchName.observe(this) { + viewModel.selectedBranch.observe(this) { viewBinding.headerChapters?.subtitle = it viewBinding.textViewSubtitle?.textAndVisible = it } @@ -124,7 +127,7 @@ class DetailsActivity : viewBinding.buttonDropdown.isVisible = it.size > 1 } viewModel.chapters.observe(this, PrefetchObserver(this)) - viewModel.onDownloadStarted.observe(this, DownloadStartedObserver(viewBinding.containerDetails)) + viewModel.onDownloadStarted.observeEvent(this, DownloadStartedObserver(viewBinding.containerDetails)) addMenuProvider( DetailsMenuProvider( @@ -165,12 +168,12 @@ class DetailsActivity : } R.id.action_pages_thumbs -> { - val history = viewModel.historyInfo.value?.history + val history = viewModel.historyInfo.value.history PagesThumbnailsSheet.show( fm = supportFragmentManager, manga = viewModel.manga.value ?: return false, chapterId = history?.chapterId - ?: viewModel.chapters.value?.firstOrNull()?.chapter?.id + ?: viewModel.chapters.value.firstOrNull()?.chapter?.id ?: return false, currentPage = history?.page ?: 0, ) @@ -253,14 +256,14 @@ class DetailsActivity : .setCancelable(true) .setNegativeButton(android.R.string.cancel, null) .setTitle(R.string.translations) - .setItems(viewModel.branches.value.orEmpty()) + .setItems(viewModel.branches.value) .create() .also { it.show() } } private fun openReader(isIncognitoMode: Boolean) { val manga = viewModel.manga.value ?: return - val chapterId = viewModel.historyInfo.value?.history?.chapterId + val chapterId = viewModel.historyInfo.value.history?.chapterId if (chapterId != null && manga.chapters?.none { x -> x.id == chapterId } == true) { val snackbar = makeSnackbar(getString(R.string.chapter_is_missing), Snackbar.LENGTH_SHORT) snackbar.show() @@ -301,11 +304,11 @@ class DetailsActivity : private class PrefetchObserver( private val context: Context, - ) : Observer?> { + ) : FlowCollector?> { private var isCalled = false - override fun onChanged(value: List?) { + override suspend fun emit(value: List?) { if (value.isNullOrEmpty()) { return } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt index 875e7fb7a..dbd6318e3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt @@ -18,6 +18,7 @@ import coil.request.ImageRequest import coil.util.CoilUtils import com.google.android.material.chip.Chip import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.filterNotNull import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter @@ -34,6 +35,7 @@ import org.koitharu.kotatsu.core.util.ext.drawableTop import org.koitharu.kotatsu.core.util.ext.enqueueWith import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty import org.koitharu.kotatsu.core.util.ext.measureHeight +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.resolveDp import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.core.util.ext.textAndVisible @@ -42,7 +44,7 @@ import org.koitharu.kotatsu.details.ui.model.ChapterListItem import org.koitharu.kotatsu.details.ui.model.HistoryInfo import org.koitharu.kotatsu.details.ui.scrobbling.ScrobblingItemDecoration import org.koitharu.kotatsu.details.ui.scrobbling.ScrollingInfoAdapter -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.image.ui.ImageActivity import org.koitharu.kotatsu.main.ui.owners.NoModalBottomSheetOwner import org.koitharu.kotatsu.parsers.model.Manga @@ -82,7 +84,7 @@ class DetailsFragment : binding.infoLayout.textViewSource.setOnClickListener(this) binding.textViewDescription.movementMethod = LinkMovementMethod.getInstance() binding.chipsTags.onChipClickListener = this - viewModel.manga.observe(viewLifecycleOwner, ::onMangaUpdated) + viewModel.manga.filterNotNull().observe(viewLifecycleOwner, ::onMangaUpdated) viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged) viewModel.historyInfo.observe(viewLifecycleOwner, ::onHistoryChanged) viewModel.bookmarks.observe(viewLifecycleOwner, ::onBookmarksChanged) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt index 927e9b80c..7579b3301 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt @@ -7,10 +7,7 @@ import android.text.style.ForegroundColorSpan import androidx.core.net.toUri import androidx.core.text.getSpans import androidx.core.text.parseAsHtml -import androidx.lifecycle.LiveData import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.asFlow -import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers @@ -18,9 +15,9 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChangedBy -import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map @@ -31,27 +28,28 @@ import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository -import org.koitharu.kotatsu.core.model.DoubleManga import org.koitharu.kotatsu.core.model.getPreferredBranch import org.koitharu.kotatsu.core.parser.MangaIntent import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.core.prefs.observeAsFlow +import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.computeSize import org.koitharu.kotatsu.core.util.ext.requireValue import org.koitharu.kotatsu.core.util.ext.toFileOrNull import org.koitharu.kotatsu.details.domain.BranchComparator import org.koitharu.kotatsu.details.domain.DetailsInteractor +import org.koitharu.kotatsu.details.domain.DoubleMangaLoadUseCase +import org.koitharu.kotatsu.details.domain.model.DoubleManga import org.koitharu.kotatsu.details.ui.model.ChapterListItem import org.koitharu.kotatsu.details.ui.model.HistoryInfo import org.koitharu.kotatsu.details.ui.model.MangaBranch import org.koitharu.kotatsu.download.ui.worker.DownloadWorker -import org.koitharu.kotatsu.history.domain.HistoryRepository -import org.koitharu.kotatsu.local.data.LocalManga +import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.local.data.LocalStorageChanges -import org.koitharu.kotatsu.local.domain.DoubleMangaLoader +import org.koitharu.kotatsu.local.domain.DeleteLocalMangaUseCase +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo @@ -69,7 +67,8 @@ class DetailsViewModel @Inject constructor( private val downloadScheduler: DownloadWorker.Scheduler, private val interactor: DetailsInteractor, savedStateHandle: SavedStateHandle, - private val mangaLoader: DoubleMangaLoader, + private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase, + private val doubleMangaLoadUseCase: DoubleMangaLoadUseCase, ) : BaseViewModel() { private val intent = MangaIntent(savedStateHandle) @@ -77,47 +76,46 @@ class DetailsViewModel @Inject constructor( private val doubleManga: MutableStateFlow = MutableStateFlow(intent.manga?.let { DoubleManga(it) }) private var loadingJob: Job - val onShowToast = SingleLiveEvent() - val onDownloadStarted = SingleLiveEvent() + val onShowToast = MutableEventFlow() + val onDownloadStarted = MutableEventFlow() - private val mangaData = doubleManga.map { it?.any } + val manga = doubleManga.map { it?.any } .stateIn(viewModelScope, SharingStarted.Eagerly, doubleManga.value?.any) - private val history = historyRepository.observeOne(mangaId) + val history = historyRepository.observeOne(mangaId) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null) - private val favourite = interactor.observeIsFavourite(mangaId) + val favouriteCategories = interactor.observeIsFavourite(mangaId) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false) - private val newChapters = interactor.observeNewChapters(mangaId) + val newChaptersCount = interactor.observeNewChapters(mangaId) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, 0) private val chaptersQuery = MutableStateFlow("") - private val selectedBranch = MutableStateFlow(null) + val selectedBranch = MutableStateFlow(null) - private val chaptersReversed = settings.observeAsFlow(AppSettings.KEY_REVERSE_CHAPTERS) { chaptersReverse } - .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false) - - val manga = mangaData.filterNotNull().asLiveData(viewModelScope.coroutineContext) - val favouriteCategories = favourite.asLiveData(viewModelScope.coroutineContext) - val newChaptersCount = newChapters.asLiveData(viewModelScope.coroutineContext) - val isChaptersReversed = chaptersReversed.asLiveData(viewModelScope.coroutineContext) + val isChaptersReversed = settings.observeAsStateFlow( + scope = viewModelScope + Dispatchers.Default, + key = AppSettings.KEY_REVERSE_CHAPTERS, + valueProducer = { chaptersReverse }, + ) - val historyInfo: LiveData = combine( - mangaData, + val historyInfo: StateFlow = combine( + manga, selectedBranch, history, - interactor.observeIncognitoMode(mangaData), + interactor.observeIncognitoMode(manga), ) { m, b, h, im -> HistoryInfo(m, b, h, im) - }.asFlowLiveData( - context = viewModelScope.coroutineContext + Dispatchers.Default, - defaultValue = HistoryInfo(null, null, null, false), + }.stateIn( + scope = viewModelScope + Dispatchers.Default, + started = SharingStarted.Eagerly, + initialValue = HistoryInfo(null, null, null, false), ) - val bookmarks = mangaData.flatMapLatest { + val bookmarks = manga.flatMapLatest { if (it != null) bookmarksRepository.observeBookmarks(it) else flowOf(emptyList()) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, emptyList()) val localSize = doubleManga .map { @@ -128,9 +126,9 @@ class DetailsViewModel @Inject constructor( } else { 0L } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, 0) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.WhileSubscribed(), 0) - val description = mangaData + val description = manga .distinctUntilChangedBy { it?.description.orEmpty() } .transformLatest { val description = it?.description @@ -140,16 +138,16 @@ class DetailsViewModel @Inject constructor( emit(description.parseAsHtml().filterSpans()) emit(description.parseAsHtml(imageGetter = imageGetter).filterSpans()) } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, null) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.WhileSubscribed(5000), null) - val onMangaRemoved = SingleLiveEvent() + val onMangaRemoved = MutableEventFlow() val isScrobblingAvailable: Boolean get() = scrobblers.any { it.isAvailable } - val scrobblingInfo: LiveData> = interactor.observeScrobblingInfo(mangaId) - .asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) + val scrobblingInfo: StateFlow> = interactor.observeScrobblingInfo(mangaId) + .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList()) - val branches: LiveData> = combine( + val branches: StateFlow> = combine( doubleManga, selectedBranch, ) { m, b -> @@ -158,32 +156,29 @@ class DetailsViewModel @Inject constructor( chapters.groupBy { x -> x.branch } .map { x -> MangaBranch(x.key, x.value.size, x.key == b) } .sortedWith(BranchComparator()) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) - - val selectedBranchName = selectedBranch - .asFlowLiveData(viewModelScope.coroutineContext, null) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList()) - val isChaptersEmpty: LiveData = combine( + val isChaptersEmpty: StateFlow = combine( doubleManga, - isLoading.asFlow(), + isLoading, ) { manga, loading -> manga?.any != null && manga.chapters.isNullOrEmpty() && !loading - }.asFlowLiveData(viewModelScope.coroutineContext, false) + }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false) val chapters = combine( combine( doubleManga, history, selectedBranch, - newChapters, + newChaptersCount, ) { manga, history, branch, news -> mapChapters(manga?.remote, manga?.local, history, news, branch) }, - chaptersReversed, + isChaptersReversed, chaptersQuery, ) { list, reversed, query -> (if (reversed) list.asReversed() else list).filterSearch(query) - }.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default) + }.stateIn(viewModelScope, SharingStarted.Eagerly, emptyList()) val selectedBranchValue: String? get() = selectedBranch.value @@ -208,8 +203,8 @@ class DetailsViewModel @Inject constructor( return } launchLoadingJob(Dispatchers.Default) { - interactor.deleteLocalManga(m) - onMangaRemoved.emitCall(m) + deleteLocalMangaUseCase(m) + onMangaRemoved.call(m) } } @@ -276,12 +271,12 @@ class DetailsViewModel @Inject constructor( doubleManga.requireValue().requireAny(), chaptersIds, ) - onDownloadStarted.emitCall(Unit) + onDownloadStarted.call(Unit) } } private fun doLoad() = launchLoadingJob(Dispatchers.Default) { - val result = mangaLoader.load(intent) + val result = doubleMangaLoadUseCase(intent) val manga = result.requireAny() // find default branch val hist = historyRepository.getOne(manga) @@ -317,7 +312,7 @@ class DetailsViewModel @Inject constructor( } private fun getScrobbler(index: Int): Scrobbler? { - val info = scrobblingInfo.value?.getOrNull(index) + val info = scrobblingInfo.value.getOrNull(index) val scrobbler = if (info != null) { scrobblers.find { it.scrobblerService == info.scrobbler && it.isAvailable } } else { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/scrobbling/ScrobblingInfoBottomSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/scrobbling/ScrobblingInfoBottomSheet.kt index 96950f5ad..045fb420d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/scrobbling/ScrobblingInfoBottomSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/scrobbling/ScrobblingInfoBottomSheet.kt @@ -21,6 +21,8 @@ import org.koitharu.kotatsu.core.ui.BaseBottomSheet import org.koitharu.kotatsu.core.util.ext.enqueueWith import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.newImageRequest +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.SheetScrobblingBinding @@ -59,7 +61,7 @@ class ScrobblingInfoBottomSheet : override fun onViewBindingCreated(binding: SheetScrobblingBinding, savedInstanceState: Bundle?) { super.onViewBindingCreated(binding, savedInstanceState) viewModel.scrobblingInfo.observe(viewLifecycleOwner, ::onScrobblingInfoChanged) - viewModel.onError.observe(viewLifecycleOwner) { + viewModel.onError.observeEvent(viewLifecycleOwner) { Toast.makeText(binding.root.context, it.getDisplayMessage(binding.root.resources), Toast.LENGTH_SHORT) .show() } @@ -105,7 +107,7 @@ class ScrobblingInfoBottomSheet : when (v.id) { R.id.button_menu -> menu?.show() R.id.imageView_cover -> { - val coverUrl = viewModel.scrobblingInfo.value?.getOrNull(scrobblerIndex)?.coverUrl ?: return + val coverUrl = viewModel.scrobblingInfo.value.getOrNull(scrobblerIndex)?.coverUrl ?: return val options = scaleUpActivityOptionsOf(v) startActivity(ImageActivity.newIntent(v.context, coverUrl, null), options.toBundle()) } @@ -135,7 +137,7 @@ class ScrobblingInfoBottomSheet : override fun onMenuItemClick(item: MenuItem): Boolean { when (item.itemId) { R.id.action_browser -> { - val url = viewModel.scrobblingInfo.value?.getOrNull(scrobblerIndex)?.externalUrl ?: return false + val url = viewModel.scrobblingInfo.value.getOrNull(scrobblerIndex)?.externalUrl ?: return false val intent = Intent(Intent.ACTION_VIEW, url.toUri()) startActivity( Intent.createChooser(intent, getString(R.string.open_in_browser)), @@ -149,7 +151,7 @@ class ScrobblingInfoBottomSheet : R.id.action_edit -> { val manga = viewModel.manga.value ?: return false - val scrobblerService = viewModel.scrobblingInfo.value?.getOrNull(scrobblerIndex)?.scrobbler + val scrobblerService = viewModel.scrobblingInfo.value.getOrNull(scrobblerIndex)?.scrobbler ScrobblingSelectorBottomSheet.show(parentFragmentManager, manga, scrobblerService) dismiss() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/domain/DownloadState.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/domain/DownloadState.kt index fea793f6d..8adf4a953 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/domain/DownloadState.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/domain/DownloadState.kt @@ -1,8 +1,8 @@ package org.koitharu.kotatsu.download.domain import androidx.work.Data -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE -import org.koitharu.kotatsu.local.data.LocalManga +import org.koitharu.kotatsu.history.data.PROGRESS_NONE +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import java.util.Date diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt index 6fb8ecb9d..5a6128b75 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt @@ -11,14 +11,16 @@ import androidx.annotation.Px import androidx.appcompat.view.ActionMode import androidx.core.graphics.Insets import androidx.core.view.updatePadding -import androidx.lifecycle.Observer import coil.ImageLoader import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.FlowCollector import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.ActivityDownloadsBinding import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.download.ui.worker.PausingReceiver @@ -61,8 +63,8 @@ class DownloadsActivity : BaseActivity(), viewModel.items.observe(this) { downloadsAdapter.items = it } - viewModel.onActionDone.observe(this, ReversibleActionObserver(viewBinding.recyclerView)) - val menuObserver = Observer { _ -> invalidateOptionsMenu() } + viewModel.onActionDone.observeEvent(this, ReversibleActionObserver(viewBinding.recyclerView)) + val menuObserver = FlowCollector { _ -> invalidateOptionsMenu() } viewModel.hasActiveWorks.observe(this, menuObserver) viewModel.hasPausedWorks.observe(this, menuObserver) viewModel.hasCancellableWorks.observe(this, menuObserver) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt index fb6e455ff..24b3dc68f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt @@ -20,8 +20,8 @@ import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.model.DateTimeAgo import org.koitharu.kotatsu.core.ui.util.ReversibleAction -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.daysDiff import org.koitharu.kotatsu.download.domain.DownloadState import org.koitharu.kotatsu.download.ui.worker.DownloadWorker @@ -47,23 +47,23 @@ class DownloadsViewModel @Inject constructor( .mapLatest { it.toDownloadsList() } .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null) - val onActionDone = SingleLiveEvent() + val onActionDone = MutableEventFlow() val items = works.map { it?.toUiList() ?: listOf(LoadingState) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) val hasPausedWorks = works.map { it?.any { x -> x.canResume } == true - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.WhileSubscribed(5000), false) val hasActiveWorks = works.map { it?.any { x -> x.canPause } == true - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.WhileSubscribed(5000), false) val hasCancellableWorks = works.map { it?.any { x -> !x.workState.isFinished } == true - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.WhileSubscribed(5000), false) fun cancel(id: UUID) { launchJob(Dispatchers.Default) { @@ -79,14 +79,14 @@ class DownloadsViewModel @Inject constructor( workScheduler.cancel(work.id) } } - onActionDone.emitCall(ReversibleAction(R.string.downloads_cancelled, null)) + onActionDone.call(ReversibleAction(R.string.downloads_cancelled, null)) } } fun cancelAll() { launchJob(Dispatchers.Default) { workScheduler.cancelAll() - onActionDone.emitCall(ReversibleAction(R.string.downloads_cancelled, null)) + onActionDone.call(ReversibleAction(R.string.downloads_cancelled, null)) } } @@ -146,14 +146,14 @@ class DownloadsViewModel @Inject constructor( workScheduler.delete(work.id) } } - onActionDone.emitCall(ReversibleAction(R.string.downloads_removed, null)) + onActionDone.call(ReversibleAction(R.string.downloads_removed, null)) } } fun removeCompleted() { launchJob(Dispatchers.Default) { workScheduler.removeCompleted() - onActionDone.emitCall(ReversibleAction(R.string.downloads_removed, null)) + onActionDone.call(ReversibleAction(R.string.downloads_removed, null)) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadStartedObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadStartedObserver.kt index 10dbb2292..6c42b9275 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadStartedObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadStartedObserver.kt @@ -1,8 +1,8 @@ package org.koitharu.kotatsu.download.ui.worker import android.view.View -import androidx.lifecycle.Observer import com.google.android.material.snackbar.Snackbar +import kotlinx.coroutines.flow.FlowCollector import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.util.ext.findActivity import org.koitharu.kotatsu.download.ui.list.DownloadsActivity @@ -10,9 +10,9 @@ import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner class DownloadStartedObserver( private val snackbarHost: View, -) : Observer { +) : FlowCollector { - override fun onChanged(value: Unit) { + override suspend fun emit(value: Unit) { val snackbar = Snackbar.make(snackbarHost, R.string.download_started, Snackbar.LENGTH_LONG) (snackbarHost.context.findActivity() as? BottomNavOwner)?.let { snackbar.anchorView = it.bottomNav diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt index 47cf46cf0..0d620188d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt @@ -48,12 +48,12 @@ import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty import org.koitharu.kotatsu.core.util.ext.writeAllCancellable import org.koitharu.kotatsu.core.util.progress.TimeLeftEstimator import org.koitharu.kotatsu.download.domain.DownloadState -import org.koitharu.kotatsu.local.data.LocalManga +import org.koitharu.kotatsu.local.data.LocalMangaRepository import org.koitharu.kotatsu.local.data.LocalStorageChanges import org.koitharu.kotatsu.local.data.PagesCache import org.koitharu.kotatsu.local.data.input.LocalMangaInput import org.koitharu.kotatsu.local.data.output.LocalMangaOutput -import org.koitharu.kotatsu.local.domain.LocalMangaRepository +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaSource diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/explore/domain/ExploreRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/explore/domain/ExploreRepository.kt index e3ea1c156..de68c4097 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/explore/domain/ExploreRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/explore/domain/ExploreRepository.kt @@ -4,7 +4,7 @@ import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.ext.almostEquals import org.koitharu.kotatsu.core.util.ext.asArrayList -import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.util.runCatchingCancellable diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt index d0159e851..69b6c9d5c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt @@ -25,6 +25,8 @@ import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver import org.koitharu.kotatsu.core.ui.util.SpanSizeResolver import org.koitharu.kotatsu.core.util.ext.addMenuProvider +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.FragmentExploreBinding import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.explore.ui.adapter.ExploreAdapter @@ -74,9 +76,9 @@ class ExploreFragment : viewModel.content.observe(viewLifecycleOwner) { exploreAdapter?.items = it } - viewModel.onError.observe(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) - viewModel.onOpenManga.observe(viewLifecycleOwner, ::onOpenManga) - viewModel.onActionDone.observe(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView)) + viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) + viewModel.onOpenManga.observeEvent(viewLifecycleOwner, ::onOpenManga) + viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView)) viewModel.isGrid.observe(viewLifecycleOwner, ::onGridModeChanged) viewModel.onShowSuggestionsTip.observe(viewLifecycleOwner) { showSuggestionsTip() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt index 6ee8eb2b8..0f163d92f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt @@ -1,16 +1,17 @@ package org.koitharu.kotatsu.explore.ui -import androidx.lifecycle.LiveData -import androidx.lifecycle.asFlow import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.prefs.AppSettings @@ -18,8 +19,8 @@ import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.util.ReversibleAction import org.koitharu.kotatsu.core.ui.util.ReversibleHandle -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.explore.domain.ExploreRepository import org.koitharu.kotatsu.explore.ui.model.ExploreItem import org.koitharu.kotatsu.parsers.model.Manga @@ -34,29 +35,28 @@ class ExploreViewModel @Inject constructor( private val exploreRepository: ExploreRepository, ) : BaseViewModel() { - private val gridMode = settings.observeAsStateFlow( + val isGrid = settings.observeAsStateFlow( key = AppSettings.KEY_SOURCES_GRID, scope = viewModelScope + Dispatchers.IO, valueProducer = { isSourcesGridMode }, ) - val onOpenManga = SingleLiveEvent() - val onActionDone = SingleLiveEvent() - val onShowSuggestionsTip = SingleLiveEvent() - val isGrid = gridMode.asFlowLiveData(viewModelScope.coroutineContext) + val onOpenManga = MutableEventFlow() + val onActionDone = MutableEventFlow() + val onShowSuggestionsTip = MutableEventFlow() - val content: LiveData> = isLoading.asFlow().flatMapLatest { loading -> + val content: StateFlow> = isLoading.flatMapLatest { loading -> if (loading) { flowOf(listOf(ExploreItem.Loading)) } else { createContentFlow() } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(ExploreItem.Loading)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(ExploreItem.Loading)) init { launchJob(Dispatchers.Default) { if (!settings.isSuggestionsEnabled && settings.isTipEnabled(TIP_SUGGESTIONS)) { - onShowSuggestionsTip.emitCall(Unit) + onShowSuggestionsTip.call(Unit) } } } @@ -64,7 +64,7 @@ class ExploreViewModel @Inject constructor( fun openRandom() { launchLoadingJob(Dispatchers.Default) { val manga = exploreRepository.findRandomManga(tagsLimit = 8) - onOpenManga.emitCall(manga) + onOpenManga.call(manga) } } @@ -74,7 +74,7 @@ class ExploreViewModel @Inject constructor( val rollback = ReversibleHandle { settings.hiddenSources -= source.name } - onActionDone.emitCall(ReversibleAction(R.string.source_disabled, rollback)) + onActionDone.call(ReversibleAction(R.string.source_disabled, rollback)) } } @@ -95,7 +95,7 @@ class ExploreViewModel @Inject constructor( } .onStart { emit("") } .map { settings.getMangaSources(includeHidden = false) } - .combine(gridMode) { content, grid -> buildList(content, grid) } + .combine(isGrid) { content, grid -> buildList(content, grid) } private fun buildList(sources: List, isGrid: Boolean): List { val result = ArrayList(sources.size + 3) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/FavouriteCategoriesActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/FavouriteCategoriesActivity.kt index 66901002d..2675851ae 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/FavouriteCategoriesActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/FavouriteCategoriesActivity.kt @@ -24,6 +24,8 @@ import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.list.ListSelectionController +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.databinding.ActivityCategoriesBinding import org.koitharu.kotatsu.favourites.ui.FavouritesActivity @@ -71,7 +73,7 @@ class FavouriteCategoriesActivity : onBackPressedDispatcher.addCallback(exitReorderModeCallback) viewModel.detalizedCategories.observe(this, ::onCategoriesChanged) - viewModel.onError.observe(this, SnackbarErrorObserver(viewBinding.recyclerView, null)) + viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.recyclerView, null)) viewModel.isInReorderMode.observe(this, ::onReorderModeChanged) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt index e2057a28c..f7a397df0 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt @@ -1,17 +1,17 @@ package org.koitharu.kotatsu.favourites.ui.categories -import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.asFlowLiveData -import org.koitharu.kotatsu.core.util.ext.mapItems import org.koitharu.kotatsu.core.util.ext.requireValue import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.ui.categories.adapter.CategoryListModel @@ -27,23 +27,11 @@ class FavouritesCategoriesViewModel @Inject constructor( ) : BaseViewModel() { private var reorderJob: Job? = null - private val isReorder = MutableStateFlow(false) - - val isInReorderMode = isReorder.asLiveData(viewModelScope.coroutineContext) - - val allCategories = repository.observeCategories() - .mapItems { - CategoryListModel( - mangaCount = 0, - covers = listOf(), - category = it, - isReorderMode = false, - ) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) + val isInReorderMode = MutableStateFlow(false) val detalizedCategories = combine( repository.observeCategoriesWithCovers(), - isReorder, + isInReorderMode, ) { list, reordering -> list.map { (category, covers) -> CategoryListModel( @@ -62,7 +50,7 @@ class FavouritesCategoriesViewModel @Inject constructor( ), ) } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) fun deleteCategory(id: Long) { launchJob { @@ -80,12 +68,12 @@ class FavouritesCategoriesViewModel @Inject constructor( settings.isAllFavouritesVisible = isVisible } - fun isInReorderMode(): Boolean = isReorder.value + fun isInReorderMode(): Boolean = isInReorderMode.value - fun isEmpty(): Boolean = detalizedCategories.value?.none { it is CategoryListModel } ?: true + fun isEmpty(): Boolean = detalizedCategories.value.none { it is CategoryListModel } fun setReorderMode(isReorderMode: Boolean) { - isReorder.value = isReorderMode + isInReorderMode.value = isReorderMode } fun reorderCategories(oldPos: Int, newPos: Int) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/edit/FavouritesCategoryEditActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/edit/FavouritesCategoryEditActivity.kt index d7980dfcb..3b055ddff 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/edit/FavouritesCategoryEditActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/edit/FavouritesCategoryEditActivity.kt @@ -22,6 +22,8 @@ import org.koitharu.kotatsu.core.ui.model.titleRes import org.koitharu.kotatsu.core.ui.util.DefaultTextWatcher import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.getSerializableCompat +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.setChecked import org.koitharu.kotatsu.databinding.ActivityCategoryEditBinding import org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesActivity @@ -50,10 +52,10 @@ class FavouritesCategoryEditActivity : viewBinding.editName.addTextChangedListener(this) afterTextChanged(viewBinding.editName.text) - viewModel.onSaved.observe(this) { finishAfterTransition() } + viewModel.onSaved.observeEvent(this) { finishAfterTransition() } viewModel.category.observe(this, ::onCategoryChanged) viewModel.isLoading.observe(this, ::onLoadingStateChanged) - viewModel.onError.observe(this, ::onError) + viewModel.onError.observeEvent(this, ::onError) viewModel.isTrackerEnabled.observe(this) { viewBinding.switchTracker.isVisible = it } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/edit/FavouritesCategoryEditViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/edit/FavouritesCategoryEditViewModel.kt index 2677f1cd0..2b32a3d5c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/edit/FavouritesCategoryEditViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/edit/FavouritesCategoryEditViewModel.kt @@ -1,16 +1,19 @@ package org.koitharu.kotatsu.favourites.ui.categories.edit -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.liveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.ext.emitValue +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditActivity.Companion.EXTRA_ID import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditActivity.Companion.NO_ID @@ -26,22 +29,20 @@ class FavouritesCategoryEditViewModel @Inject constructor( private val categoryId = savedStateHandle[EXTRA_ID] ?: NO_ID - val onSaved = SingleLiveEvent() - val category = MutableLiveData() + val onSaved = MutableEventFlow() + val category = MutableStateFlow(null) - val isTrackerEnabled = liveData(viewModelScope.coroutineContext + Dispatchers.Default) { + val isTrackerEnabled = flow { emit(settings.isTrackerEnabled && AppSettings.TRACK_FAVOURITES in settings.trackSources) - } + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false) init { launchLoadingJob(Dispatchers.Default) { - category.emitValue( - if (categoryId != NO_ID) { - repository.getCategory(categoryId) - } else { - null - }, - ) + category.value = if (categoryId != NO_ID) { + repository.getCategory(categoryId) + } else { + null + } } } @@ -58,7 +59,7 @@ class FavouritesCategoryEditViewModel @Inject constructor( } else { repository.updateCategory(categoryId, title, sortOrder, isTrackerEnabled, isVisibleOnShelf) } - onSaved.emitCall(Unit) + onSaved.call(Unit) } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesBottomSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesBottomSheet.kt index 2c9b5f4d5..983246319 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesBottomSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesBottomSheet.kt @@ -15,6 +15,8 @@ import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.ui.BaseBottomSheet import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.util.ext.getDisplayMessage +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.SheetFavoriteCategoriesBinding import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditActivity @@ -46,7 +48,7 @@ class FavouriteCategoriesBottomSheet : binding.headerBar.toolbar.setOnMenuItemClickListener(this) viewModel.content.observe(viewLifecycleOwner, this::onContentChanged) - viewModel.onError.observe(viewLifecycleOwner, ::onError) + viewModel.onError.observeEvent(viewLifecycleOwner, ::onError) } override fun onDestroyView() { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt index 32a7f0f11..69180f1aa 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt @@ -4,11 +4,13 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.core.model.ids import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.asFlowLiveData import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet.Companion.KEY_MANGA_LIST import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem @@ -33,7 +35,7 @@ class MangaCategoriesViewModel @Inject constructor( isChecked = it.id in checked, ) } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList()) fun setChecked(categoryId: Long, isChecked: Boolean) { launchJob(Dispatchers.Default) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListFragment.kt index 77c128fe5..9e22b6a62 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListFragment.kt @@ -12,6 +12,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.ui.model.titleRes import org.koitharu.kotatsu.core.util.ext.addMenuProvider +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.FragmentListBinding import org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesActivity diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt index b8e310dcb..3c7ceb019 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt @@ -1,25 +1,28 @@ package org.koitharu.kotatsu.favourites.ui.list -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.util.ReversibleAction -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.ARG_CATEGORY_ID import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.NO_ID -import org.koitharu.kotatsu.history.domain.HistoryRepository -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState @@ -43,12 +46,12 @@ class FavouritesListViewModel @Inject constructor( val categoryId: Long = savedStateHandle[ARG_CATEGORY_ID] ?: NO_ID - val sortOrder: LiveData = if (categoryId == NO_ID) { - MutableLiveData(null) + val sortOrder: StateFlow = if (categoryId == NO_ID) { + MutableStateFlow(null) } else { repository.observeCategory(categoryId) .map { it?.order } - .asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, null) + .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null) } override val content = combine( @@ -57,7 +60,7 @@ class FavouritesListViewModel @Inject constructor( } else { repository.observeAll(categoryId) }, - listModeFlow, + listMode, ) { list, mode -> when { list.isEmpty() -> listOf( @@ -77,7 +80,7 @@ class FavouritesListViewModel @Inject constructor( } }.catch { emit(listOf(it.toErrorState(canRetry = false))) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) override fun onRefresh() = Unit @@ -93,7 +96,7 @@ class FavouritesListViewModel @Inject constructor( } else { repository.removeFromCategory(categoryId, ids) } - onActionDone.emitCall(ReversibleAction(R.string.removed_from_favourites, handle)) + onActionDone.call(ReversibleAction(R.string.removed_from_favourites, handle)) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt similarity index 96% rename from app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryRepository.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt index 3cc4a81b0..f8977fabf 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.history.domain +package org.koitharu.kotatsu.history.data import androidx.room.withTransaction import dagger.Reusable @@ -17,8 +17,7 @@ import org.koitharu.kotatsu.core.model.MangaHistory import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.util.ReversibleHandle import org.koitharu.kotatsu.core.util.ext.mapItems -import org.koitharu.kotatsu.history.data.HistoryEntity -import org.koitharu.kotatsu.history.data.toMangaHistory +import org.koitharu.kotatsu.history.domain.model.MangaWithHistory import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryUpdateUseCase.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryUpdateUseCase.kt new file mode 100644 index 000000000..a28d27fb8 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryUpdateUseCase.kt @@ -0,0 +1,38 @@ +package org.koitharu.kotatsu.history.domain + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.koitharu.kotatsu.core.util.ext.processLifecycleScope +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.parsers.util.runCatchingCancellable +import org.koitharu.kotatsu.reader.ui.ReaderState +import org.koitharu.kotatsu.util.ext.printStackTraceDebug +import javax.inject.Inject + +class HistoryUpdateUseCase @Inject constructor( + private val historyRepository: HistoryRepository, +) { + + suspend operator fun invoke(manga: Manga, readerState: ReaderState, percent: Float) { + historyRepository.addOrUpdate( + manga = manga, + chapterId = readerState.chapterId, + page = readerState.page, + scroll = readerState.scroll, + percent = percent, + ) + } + + fun invokeAsync( + manga: Manga, + readerState: ReaderState, + percent: Float + ) = processLifecycleScope.launch(Dispatchers.Default) { + runCatchingCancellable { + invoke(manga, readerState, percent) + }.onFailure { + it.printStackTraceDebug() + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/MangaWithHistory.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/model/MangaWithHistory.kt similarity index 77% rename from app/src/main/kotlin/org/koitharu/kotatsu/history/domain/MangaWithHistory.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/history/domain/model/MangaWithHistory.kt index 611dd1ded..5a7e26897 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/MangaWithHistory.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/model/MangaWithHistory.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.history.domain +package org.koitharu.kotatsu.history.domain.model import org.koitharu.kotatsu.core.model.MangaHistory import org.koitharu.kotatsu.parsers.model.Manga @@ -6,4 +6,4 @@ import org.koitharu.kotatsu.parsers.model.Manga data class MangaWithHistory( val manga: Manga, val history: MangaHistory -) \ No newline at end of file +) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListFragment.kt index de17fc3ed..47157c4a7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListFragment.kt @@ -9,6 +9,7 @@ import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.util.ext.addMenuProvider +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.databinding.FragmentListBinding import org.koitharu.kotatsu.list.ui.MangaListFragment import org.koitharu.kotatsu.parsers.model.MangaSource diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt index da09bea62..c46f349db 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt @@ -1,28 +1,28 @@ package org.koitharu.kotatsu.history.ui -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ListMode -import org.koitharu.kotatsu.core.prefs.observeAsFlow +import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.model.DateTimeAgo import org.koitharu.kotatsu.core.ui.util.ReversibleAction -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.daysDiff -import org.koitharu.kotatsu.core.util.ext.emitValue import org.koitharu.kotatsu.core.util.ext.onFirst import org.koitharu.kotatsu.download.ui.worker.DownloadWorker -import org.koitharu.kotatsu.history.domain.HistoryRepository -import org.koitharu.kotatsu.history.domain.MangaWithHistory -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.history.data.PROGRESS_NONE +import org.koitharu.kotatsu.history.domain.model.MangaWithHistory import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel @@ -45,15 +45,16 @@ class HistoryListViewModel @Inject constructor( downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { - val isGroupingEnabled = MutableLiveData() - - private val historyGrouping = settings.observeAsFlow(AppSettings.KEY_HISTORY_GROUPING) { isHistoryGroupingEnabled } - .onEach { isGroupingEnabled.emitValue(it) } + val isGroupingEnabled = settings.observeAsStateFlow( + scope = viewModelScope + Dispatchers.Default, + key = AppSettings.KEY_HISTORY_GROUPING, + valueProducer = { isHistoryGroupingEnabled }, + ) override val content = combine( repository.observeAllWithHistory(), - historyGrouping, - listModeFlow, + isGroupingEnabled, + listMode, ) { list, grouped, mode -> when { list.isEmpty() -> listOf( @@ -73,7 +74,7 @@ class HistoryListViewModel @Inject constructor( loadingCounter.decrement() }.catch { emit(listOf(it.toErrorState(canRetry = false))) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) override fun onRefresh() = Unit @@ -91,7 +92,7 @@ class HistoryListViewModel @Inject constructor( } launchJob(Dispatchers.Default) { val handle = repository.delete(ids) - onActionDone.emitCall(ReversibleAction(R.string.removed_from_history, handle)) + onActionDone.call(ReversibleAction(R.string.removed_from_history, handle)) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/util/ReadingProgressDrawable.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/util/ReadingProgressDrawable.kt index dc2bd9d8e..618b8d788 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/util/ReadingProgressDrawable.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/util/ReadingProgressDrawable.kt @@ -13,7 +13,7 @@ import androidx.appcompat.content.res.AppCompatResources import androidx.core.graphics.ColorUtils import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.util.ext.scale -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.history.data.PROGRESS_NONE class ReadingProgressDrawable( context: Context, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/util/ReadingProgressView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/util/ReadingProgressView.kt index 49c05a7c5..744201215 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/util/ReadingProgressView.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/util/ReadingProgressView.kt @@ -12,7 +12,7 @@ import androidx.annotation.AttrRes import androidx.annotation.StyleRes import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.util.ext.getAnimationDuration -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.history.data.PROGRESS_NONE class ReadingProgressView @JvmOverloads constructor( context: Context, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt index c503087e3..146767467 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt @@ -37,6 +37,8 @@ import org.koitharu.kotatsu.core.util.ext.addMenuProvider import org.koitharu.kotatsu.core.util.ext.clearItemDecorations import org.koitharu.kotatsu.core.util.ext.getThemeColor import org.koitharu.kotatsu.core.util.ext.measureHeight +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.resolveDp import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope @@ -123,9 +125,9 @@ abstract class MangaListFragment : viewModel.gridScale.observe(viewLifecycleOwner, ::onGridScaleChanged) viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged) viewModel.content.observe(viewLifecycleOwner, ::onListChanged) - viewModel.onError.observe(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) - viewModel.onActionDone.observe(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView)) - viewModel.onDownloadStarted.observe(viewLifecycleOwner, DownloadStartedObserver(binding.recyclerView)) + viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) + viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView)) + viewModel.onDownloadStarted.observeEvent(viewLifecycleOwner, DownloadStartedObserver(binding.recyclerView)) } override fun onDestroyView() { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt index b123776dc..8c197fae9 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt @@ -1,39 +1,38 @@ package org.koitharu.kotatsu.list.ui -import androidx.lifecycle.LiveData import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.observeAsFlow -import org.koitharu.kotatsu.core.prefs.observeAsLiveData +import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.util.ReversibleAction -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaTag abstract class MangaListViewModel( - private val settings: AppSettings, + settings: AppSettings, private val downloadScheduler: DownloadWorker.Scheduler, ) : BaseViewModel() { - abstract val content: LiveData> - protected val listModeFlow = settings.observeAsFlow(AppSettings.KEY_LIST_MODE) { listMode } - .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, settings.listMode) - val listMode = listModeFlow.asFlowLiveData(viewModelScope.coroutineContext) - val onActionDone = SingleLiveEvent() - val gridScale = settings.observeAsLiveData( - context = viewModelScope.coroutineContext + Dispatchers.Default, + abstract val content: StateFlow> + val listMode = settings.observeAsFlow(AppSettings.KEY_LIST_MODE) { listMode } + .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, settings.listMode) + val onActionDone = MutableEventFlow() + val gridScale = settings.observeAsStateFlow( + scope = viewModelScope + Dispatchers.Default, key = AppSettings.KEY_GRID_SIZE, valueProducer = { gridSize / 100f }, ) - val onDownloadStarted = SingleLiveEvent() + val onDownloadStarted = MutableEventFlow() open fun onUpdateFilter(tags: Set) = Unit @@ -44,7 +43,7 @@ abstract class MangaListViewModel( fun download(items: Set) { launchJob(Dispatchers.Default) { downloadScheduler.schedule(items) - onDownloadStarted.emitCall(Unit) + onDownloadStarted.call(Unit) } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt index 900738327..e47650a25 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt @@ -12,7 +12,7 @@ import org.koitharu.kotatsu.core.util.ext.enqueueWith import org.koitharu.kotatsu.core.util.ext.newImageRequest import org.koitharu.kotatsu.core.util.ext.source import org.koitharu.kotatsu.databinding.ItemMangaGridBinding -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.list.ui.ItemSizeResolver import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.MangaGridModel diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt index 645ecefa4..95396fca3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt @@ -16,7 +16,7 @@ import org.koitharu.kotatsu.core.util.ext.newImageRequest import org.koitharu.kotatsu.core.util.ext.source import org.koitharu.kotatsu.core.util.ext.textAndVisible import org.koitharu.kotatsu.databinding.ItemMangaListDetailsBinding -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.MangaListDetailedModel import org.koitharu.kotatsu.parsers.model.MangaTag diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/filter/FilterBottomSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/filter/FilterBottomSheet.kt index f1dc651f7..a00341a55 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/filter/FilterBottomSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/filter/FilterBottomSheet.kt @@ -11,6 +11,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseBottomSheet import org.koitharu.kotatsu.core.ui.util.CollapseActionViewCallback +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.parentFragmentViewModels import org.koitharu.kotatsu.databinding.SheetFilterBinding import org.koitharu.kotatsu.remotelist.ui.RemoteListViewModel diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/filter/FilterCoordinator.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/filter/FilterCoordinator.kt index b8c04d96d..0ff57d7a3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/filter/FilterCoordinator.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/filter/FilterCoordinator.kt @@ -1,22 +1,25 @@ package org.koitharu.kotatsu.list.ui.filter import androidx.annotation.WorkerThread -import androidx.lifecycle.LiveData import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.parser.RemoteMangaRepository -import org.koitharu.kotatsu.core.util.asFlowLiveData import org.koitharu.kotatsu.parsers.model.MangaTag +import org.koitharu.kotatsu.parsers.util.SuspendLazy import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.util.ext.printStackTraceDebug import java.text.Collator @@ -31,13 +34,13 @@ class FilterCoordinator( private val currentState = MutableStateFlow(FilterState(repository.defaultSortOrder, emptySet())) private var searchQuery = MutableStateFlow("") - private val localTagsDeferred = coroutineScope.async(Dispatchers.Default, CoroutineStart.LAZY) { + private val localTags = SuspendLazy { dataRepository.findTags(repository.source) } private var availableTagsDeferred = loadTagsAsync() - val items: LiveData> = getItemsFlow() - .asFlowLiveData(coroutineScope.coroutineContext + Dispatchers.Default, listOf(FilterItem.Loading)) + val items: StateFlow> = getItemsFlow() + .stateIn(coroutineScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(FilterItem.Loading)) init { observeState() @@ -97,7 +100,7 @@ class FilterCoordinator( } private fun getTagsAsFlow() = flow { - val localTags = localTagsDeferred.await() + val localTags = localTags.get() emit(TagsWrapper(localTags, isLoading = true, isError = false)) val remoteTags = tryLoadTags() if (remoteTags == null) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt index 89cd7eee1..ea24b01fa 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt @@ -7,7 +7,7 @@ import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.ui.widgets.ChipsView import org.koitharu.kotatsu.core.util.ext.ifZero -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.parsers.exception.AuthRequiredException import org.koitharu.kotatsu.parsers.model.Manga diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/LocalMangaRepository.kt similarity index 95% rename from app/src/main/kotlin/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/local/data/LocalMangaRepository.kt index 6d3964978..7ac0dc282 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/LocalMangaRepository.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.local.domain +package org.koitharu.kotatsu.local.data import android.net.Uri import androidx.core.net.toFile @@ -15,13 +15,10 @@ import org.koitharu.kotatsu.core.model.isLocal import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.util.CompositeMutex import org.koitharu.kotatsu.core.util.ext.deleteAwait -import org.koitharu.kotatsu.local.data.LocalManga -import org.koitharu.kotatsu.local.data.LocalStorageChanges -import org.koitharu.kotatsu.local.data.LocalStorageManager -import org.koitharu.kotatsu.local.data.TempFileFilter import org.koitharu.kotatsu.local.data.input.LocalMangaInput import org.koitharu.kotatsu.local.data.output.LocalMangaOutput import org.koitharu.kotatsu.local.data.output.LocalMangaUtil +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaPage diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/importer/SingleMangaImporter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/importer/SingleMangaImporter.kt index e5c9bf9e1..9221a4f08 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/importer/SingleMangaImporter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/importer/SingleMangaImporter.kt @@ -16,10 +16,10 @@ import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException import org.koitharu.kotatsu.core.util.ext.resolveName import org.koitharu.kotatsu.core.util.ext.writeAllCancellable import org.koitharu.kotatsu.local.data.CbzFilter -import org.koitharu.kotatsu.local.data.LocalManga import org.koitharu.kotatsu.local.data.LocalStorageChanges import org.koitharu.kotatsu.local.data.LocalStorageManager import org.koitharu.kotatsu.local.data.input.LocalMangaInput +import org.koitharu.kotatsu.local.domain.model.LocalManga import java.io.File import java.io.IOException import javax.inject.Inject diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt index e383da294..e62943d07 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt @@ -9,9 +9,9 @@ import org.koitharu.kotatsu.core.util.ext.longHashCode import org.koitharu.kotatsu.core.util.ext.toListSorted import org.koitharu.kotatsu.local.data.CbzFilter import org.koitharu.kotatsu.local.data.ImageFileFilter -import org.koitharu.kotatsu.local.data.LocalManga import org.koitharu.kotatsu.local.data.MangaIndex import org.koitharu.kotatsu.local.data.output.LocalMangaOutput +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaPage diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaInput.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaInput.kt index 0da957b8b..f203912e5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaInput.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaInput.kt @@ -2,7 +2,7 @@ package org.koitharu.kotatsu.local.data.input import android.net.Uri import androidx.core.net.toFile -import org.koitharu.kotatsu.local.data.LocalManga +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaPage diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaZipInput.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaZipInput.kt index e768e5b9b..f468c4647 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaZipInput.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaZipInput.kt @@ -10,9 +10,9 @@ import kotlinx.coroutines.runInterruptible import org.koitharu.kotatsu.core.util.ext.longHashCode import org.koitharu.kotatsu.core.util.ext.readText import org.koitharu.kotatsu.core.util.ext.toListSorted -import org.koitharu.kotatsu.local.data.LocalManga import org.koitharu.kotatsu.local.data.MangaIndex import org.koitharu.kotatsu.local.data.output.LocalMangaOutput +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaPage diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/DeleteLocalMangaUseCase.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/DeleteLocalMangaUseCase.kt new file mode 100644 index 000000000..ef613604f --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/DeleteLocalMangaUseCase.kt @@ -0,0 +1,42 @@ +package org.koitharu.kotatsu.local.domain + +import org.koitharu.kotatsu.core.model.isLocal +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.local.data.LocalMangaRepository +import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.parsers.util.runCatchingCancellable +import org.koitharu.kotatsu.util.ext.printStackTraceDebug +import java.io.IOException +import javax.inject.Inject + +class DeleteLocalMangaUseCase @Inject constructor( + private val localMangaRepository: LocalMangaRepository, + private val historyRepository: HistoryRepository, +) { + + suspend operator fun invoke(manga: Manga) { + val victim = if (manga.isLocal) manga else localMangaRepository.findSavedManga(manga)?.manga + checkNotNull(victim) { "Cannot find saved manga for ${manga.title}" } + val original = if (manga.isLocal) localMangaRepository.getRemoteManga(manga) else manga + localMangaRepository.delete(victim) || throw IOException("Unable to delete file") + runCatchingCancellable { + historyRepository.deleteOrSwap(victim, original) + }.onFailure { + it.printStackTraceDebug() + } + } + + suspend operator fun invoke(ids: Set) { + val list = localMangaRepository.getList(0, null, null) + var removed = 0 + for (manga in list) { + if (manga.id in ids) { + invoke(manga) + removed++ + } + } + check(removed == ids.size) { + "Removed $removed files but ${ids.size} requested" + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/LocalManga.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/model/LocalManga.kt similarity index 92% rename from app/src/main/kotlin/org/koitharu/kotatsu/local/data/LocalManga.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/local/domain/model/LocalManga.kt index bebb4c12c..247d395d4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/LocalManga.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/domain/model/LocalManga.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.local.data +package org.koitharu.kotatsu.local.domain.model import androidx.core.net.toFile import androidx.core.net.toUri @@ -38,9 +38,7 @@ class LocalManga( other as LocalManga if (manga != other.manga) return false - if (file != other.file) return false - - return true + return file == other.file } override fun hashCode(): Int { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalChaptersRemoveService.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalChaptersRemoveService.kt index d63ea1100..754c8ffbb 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalChaptersRemoveService.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalChaptersRemoveService.kt @@ -15,9 +15,9 @@ import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.ui.CoroutineIntentService import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.getParcelableExtraCompat -import org.koitharu.kotatsu.local.data.LocalManga +import org.koitharu.kotatsu.local.data.LocalMangaRepository import org.koitharu.kotatsu.local.data.LocalStorageChanges -import org.koitharu.kotatsu.local.domain.LocalMangaRepository +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import javax.inject.Inject diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListFragment.kt index d451b3936..3f8fd2bb2 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListFragment.kt @@ -15,6 +15,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.util.ShareHelper import org.koitharu.kotatsu.core.util.ext.addMenuProvider +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.FragmentListBinding import org.koitharu.kotatsu.list.ui.MangaListFragment import org.koitharu.kotatsu.parsers.model.SortOrder @@ -26,7 +27,7 @@ class LocalListFragment : MangaListFragment(), PopupMenu.OnMenuItemClickListener override fun onViewBindingCreated(binding: FragmentListBinding, savedInstanceState: Bundle?) { super.onViewBindingCreated(binding, savedInstanceState) addMenuProvider(LocalListMenuProvider(this::onEmptyActionClick)) - viewModel.onMangaRemoved.observe(viewLifecycleOwner) { onItemRemoved() } + viewModel.onMangaRemoved.observeEvent(viewLifecycleOwner) { onItemRemoved() } } override fun onEmptyActionClick() { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt index 0439423eb..80836cdd7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt @@ -1,7 +1,5 @@ package org.koitharu.kotatsu.local.ui -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.asFlow import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CancellationException @@ -10,18 +8,20 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.widgets.ChipsView -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.download.ui.worker.DownloadWorker -import org.koitharu.kotatsu.history.domain.HistoryRepository -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState @@ -29,15 +29,14 @@ import org.koitharu.kotatsu.list.ui.model.ListHeader2 import org.koitharu.kotatsu.list.ui.model.LoadingState import org.koitharu.kotatsu.list.ui.model.toErrorState import org.koitharu.kotatsu.list.ui.model.toUi -import org.koitharu.kotatsu.local.data.LocalManga +import org.koitharu.kotatsu.local.data.LocalMangaRepository import org.koitharu.kotatsu.local.data.LocalStorageChanges -import org.koitharu.kotatsu.local.domain.LocalMangaRepository +import org.koitharu.kotatsu.local.domain.DeleteLocalMangaUseCase +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.SortOrder -import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.tracker.domain.TrackingRepository -import java.io.IOException import java.util.LinkedList import javax.inject.Inject @@ -49,11 +48,12 @@ class LocalListViewModel @Inject constructor( private val settings: AppSettings, private val tagHighlighter: MangaTagHighlighter, @LocalStorageChanges private val localStorageChanges: SharedFlow, + private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler), ListExtraProvider { - val onMangaRemoved = SingleLiveEvent() - val sortOrder = MutableLiveData(settings.localListOrder) + val onMangaRemoved = MutableEventFlow() + val sortOrder = MutableStateFlow(settings.localListOrder) private val listError = MutableStateFlow(null) private val mangaList = MutableStateFlow?>(null) private val selectedTags = MutableStateFlow>(emptySet()) @@ -61,8 +61,8 @@ class LocalListViewModel @Inject constructor( override val content = combine( mangaList, - listModeFlow, - sortOrder.asFlow(), + listMode, + sortOrder, selectedTags, listError, ) { list, mode, order, tags, error -> @@ -83,7 +83,7 @@ class LocalListViewModel @Inject constructor( list.toUi(this, mode, this@LocalListViewModel, tagHighlighter) } } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) init { onRefresh() @@ -120,18 +120,8 @@ class LocalListViewModel @Inject constructor( fun delete(ids: Set) { launchLoadingJob(Dispatchers.Default) { - val itemsToRemove = checkNotNull(mangaList.value).filter { it.id in ids } - for (manga in itemsToRemove) { - val original = repository.getRemoteManga(manga) - repository.delete(manga) || throw IOException("Unable to delete file") - runCatchingCancellable { - historyRepository.deleteOrSwap(manga, original) - } - mangaList.update { list -> - list?.filterNot { it.id == manga.id } - } - } - onMangaRemoved.emitCall(Unit) + deleteLocalMangaUseCase(ids) + onMangaRemoved.call(Unit) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalStorageCleanupWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalStorageCleanupWorker.kt index fc2620b27..995ac48a7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalStorageCleanupWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalStorageCleanupWorker.kt @@ -11,7 +11,7 @@ import androidx.work.WorkManager import androidx.work.WorkerParameters import dagger.assisted.Assisted import dagger.assisted.AssistedInject -import org.koitharu.kotatsu.local.domain.LocalMangaRepository +import org.koitharu.kotatsu.local.data.LocalMangaRepository import java.util.concurrent.TimeUnit @HiltWorker diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt index 9f34e0c61..024cb6994 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt @@ -45,6 +45,8 @@ import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.widgets.SlidingBottomNavigationView import org.koitharu.kotatsu.core.util.ext.drawableEnd import org.koitharu.kotatsu.core.util.ext.hideKeyboard +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.resolve import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.core.util.ext.setNavigationBarTransparentCompat @@ -137,8 +139,8 @@ class MainActivity : onFirstStart() } - viewModel.onOpenReader.observe(this, this::onOpenReader) - viewModel.onError.observe(this, SnackbarErrorObserver(viewBinding.container, null)) + viewModel.onOpenReader.observeEvent(this, this::onOpenReader) + viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.container, null)) viewModel.isLoading.observe(this, this::onLoadingStateChanged) viewModel.isResumeEnabled.observe(this, this::onResumeEnabledChanged) viewModel.counters.observe(this, ::onCountersChanged) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainViewModel.kt index f6482dce8..b983b7cbd 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainViewModel.kt @@ -5,17 +5,20 @@ import androidx.core.util.set import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException import org.koitharu.kotatsu.core.github.AppUpdateRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.observeAsFlow -import org.koitharu.kotatsu.core.prefs.observeAsLiveData +import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData -import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call +import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject @@ -24,21 +27,25 @@ import javax.inject.Inject class MainViewModel @Inject constructor( private val historyRepository: HistoryRepository, private val appUpdateRepository: AppUpdateRepository, - private val trackingRepository: TrackingRepository, - private val settings: AppSettings, + trackingRepository: TrackingRepository, + settings: AppSettings, ) : BaseViewModel() { - val onOpenReader = SingleLiveEvent() + val onOpenReader = MutableEventFlow() val isResumeEnabled = combine( historyRepository.observeHasItems(), settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled }, ) { hasItems, incognito -> hasItems && !incognito - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) + }.stateIn( + scope = viewModelScope + Dispatchers.Default, + started = SharingStarted.WhileSubscribed(5000), + initialValue = false, + ) - val isFeedAvailable = settings.observeAsLiveData( - context = viewModelScope.coroutineContext + Dispatchers.Default, + val isFeedAvailable = settings.observeAsStateFlow( + scope = viewModelScope + Dispatchers.Default, key = AppSettings.KEY_TRACKER_ENABLED, valueProducer = { isTrackerEnabled }, ) @@ -51,7 +58,11 @@ class MainViewModel @Inject constructor( a[R.id.nav_tools] = if (appUpdate != null) 1 else 0 a[R.id.nav_feed] = tracks a - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, SparseIntArray(0)) + }.stateIn( + scope = viewModelScope + Dispatchers.Default, + started = SharingStarted.WhileSubscribed(5000), + initialValue = SparseIntArray(0), + ) init { launchJob { @@ -62,7 +73,7 @@ class MainViewModel @Inject constructor( fun openLastReader() { launchLoadingJob(Dispatchers.Default) { val manga = historyRepository.getLastOrNull() ?: throw EmptyHistoryException() - onOpenReader.emitCall(manga) + onOpenReader.call(manga) } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectActivity.kt index a4a693cf5..ff6bf07bf 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectActivity.kt @@ -22,6 +22,8 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.getParcelableExtraCompat +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.ActivityProtectBinding @AndroidEntryPoint @@ -42,9 +44,9 @@ class ProtectActivity : viewBinding.buttonNext.setOnClickListener(this) viewBinding.buttonCancel.setOnClickListener(this) - viewModel.onError.observe(this, this::onError) + viewModel.onError.observeEvent(this, this::onError) viewModel.isLoading.observe(this, this::onLoadingStateChanged) - viewModel.onUnlockSuccess.observe(this) { + viewModel.onUnlockSuccess.observeEvent(this) { val intent = intent.getParcelableExtraCompat(EXTRA_INTENT) startActivity(intent) finishAfterTransition() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectViewModel.kt index e530a2a7d..7f0d8f5b5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectViewModel.kt @@ -6,7 +6,8 @@ import kotlinx.coroutines.delay import org.koitharu.kotatsu.core.exceptions.WrongPasswordException import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.parsers.util.md5 import javax.inject.Inject @@ -20,7 +21,7 @@ class ProtectViewModel @Inject constructor( private var job: Job? = null - val onUnlockSuccess = SingleLiveEvent() + val onUnlockSuccess = MutableEventFlow() val isBiometricEnabled get() = settings.isBiometricProtectionEnabled diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt index 6cff4c94f..1c75d5702 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt @@ -4,8 +4,8 @@ import android.util.LongSparseArray import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import org.koitharu.kotatsu.core.model.DoubleManga import org.koitharu.kotatsu.core.parser.MangaRepository +import org.koitharu.kotatsu.details.domain.model.DoubleManga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.reader.ui.pager.ReaderPage import javax.inject.Inject diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/DetectReaderModeUseCase.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/DetectReaderModeUseCase.kt new file mode 100644 index 000000000..fe4ad571f --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/DetectReaderModeUseCase.kt @@ -0,0 +1,97 @@ +package org.koitharu.kotatsu.reader.domain + +import android.graphics.BitmapFactory +import android.net.Uri +import android.util.Size +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runInterruptible +import okhttp3.OkHttpClient +import org.koitharu.kotatsu.core.model.findChapter +import org.koitharu.kotatsu.core.network.MangaHttpClient +import org.koitharu.kotatsu.core.parser.MangaDataRepository +import org.koitharu.kotatsu.core.parser.MangaRepository +import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.core.prefs.ReaderMode +import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.parsers.model.MangaPage +import org.koitharu.kotatsu.parsers.util.await +import org.koitharu.kotatsu.parsers.util.runCatchingCancellable +import org.koitharu.kotatsu.reader.ui.ReaderState +import org.koitharu.kotatsu.util.ext.printStackTraceDebug +import java.io.InputStream +import java.util.zip.ZipFile +import javax.inject.Inject +import kotlin.math.roundToInt + +class DetectReaderModeUseCase @Inject constructor( + private val dataRepository: MangaDataRepository, + private val settings: AppSettings, + private val mangaRepositoryFactory: MangaRepository.Factory, + @MangaHttpClient private val okHttpClient: OkHttpClient, +) { + + suspend operator fun invoke(manga: Manga, state: ReaderState?): ReaderMode { + dataRepository.getReaderMode(manga.id)?.let { return it } + val defaultMode = settings.defaultReaderMode + if (!settings.isReaderModeDetectionEnabled || defaultMode == ReaderMode.WEBTOON) { + return defaultMode + } + val chapter = state?.let { manga.findChapter(it.chapterId) } + ?: manga.chapters?.firstOrNull() + ?: error("There are no chapters in this manga") + val repo = mangaRepositoryFactory.create(manga.source) + val pages = repo.getPages(chapter) + return runCatchingCancellable { + val isWebtoon = guessMangaIsWebtoon(repo, pages) + if (isWebtoon) ReaderMode.WEBTOON else defaultMode + }.onSuccess { + dataRepository.saveReaderMode(manga, it) + }.onFailure { + it.printStackTraceDebug() + }.getOrDefault(defaultMode) + } + + /** + * Automatic determine type of manga by page size + * @return ReaderMode.WEBTOON if page is wide + */ + private suspend fun guessMangaIsWebtoon(repository: MangaRepository, pages: List): Boolean { + val pageIndex = (pages.size * 0.3).roundToInt() + val page = requireNotNull(pages.getOrNull(pageIndex)) { "No pages" } + val url = repository.getPageUrl(page) + val uri = Uri.parse(url) + val size = if (uri.scheme == "cbz") { + runInterruptible(Dispatchers.IO) { + val zip = ZipFile(uri.schemeSpecificPart) + val entry = zip.getEntry(uri.fragment) + zip.getInputStream(entry).use { + getBitmapSize(it) + } + } + } else { + val request = PageLoader.createPageRequest(page, url) + okHttpClient.newCall(request).await().use { + runInterruptible(Dispatchers.IO) { + getBitmapSize(it.body?.byteStream()) + } + } + } + return size.width * MIN_WEBTOON_RATIO < size.height + } + + companion object { + + private const val MIN_WEBTOON_RATIO = 1.8 + + private fun getBitmapSize(input: InputStream?): Size { + val options = BitmapFactory.Options().apply { + inJustDecodeBounds = true + } + BitmapFactory.decodeStream(input, null, options)?.recycle() + val imageHeight: Int = options.outHeight + val imageWidth: Int = options.outWidth + check(imageHeight > 0 && imageWidth > 0) + return Size(imageWidth, imageHeight) + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/PageSaveHelper.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/PageSaveHelper.kt index d8382a543..b312c9b12 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/PageSaveHelper.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/PageSaveHelper.kt @@ -1,6 +1,7 @@ package org.koitharu.kotatsu.reader.ui import android.content.Context +import android.graphics.BitmapFactory import android.net.Uri import android.webkit.MimeTypeMap import androidx.activity.result.ActivityResultLauncher @@ -15,7 +16,6 @@ import okio.IOException import okio.buffer import okio.sink import okio.source -import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.util.ext.writeAllCancellable import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.util.toFileNameSafe @@ -74,7 +74,7 @@ class PageSaveHelper @Inject constructor( var extension = name.substringAfterLast('.', "") name = name.substringBeforeLast('.') if (extension.length !in 2..4) { - val mimeType = MangaDataRepository.getImageMimeType(file) + val mimeType = getImageMimeType(file) extension = if (mimeType != null) { MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType) ?: EXTENSION_FALLBACK } else { @@ -83,4 +83,12 @@ class PageSaveHelper @Inject constructor( } return name.toFileNameSafe().take(MAX_FILENAME_LENGTH) + "." + extension } + + private suspend fun getImageMimeType(file: File): String? = runInterruptible(Dispatchers.IO) { + val options = BitmapFactory.Options().apply { + inJustDecodeBounds = true + } + BitmapFactory.decodeFile(file.path, options)?.recycle() + options.outMimeType + } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index 6dfb02e93..f3f655ede 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -42,9 +42,11 @@ import org.koitharu.kotatsu.core.util.IdlingDetector import org.koitharu.kotatsu.core.util.ShareHelper import org.koitharu.kotatsu.core.util.ext.hasGlobalPoint import org.koitharu.kotatsu.core.util.ext.isRtl -import org.koitharu.kotatsu.core.util.ext.observeWithPrevious +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.postDelayed import org.koitharu.kotatsu.core.util.ext.setValueRounded +import org.koitharu.kotatsu.core.util.ext.zipWithPrevious import org.koitharu.kotatsu.databinding.ActivityReaderBinding import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter @@ -108,7 +110,7 @@ class ReaderActivity : insetsDelegate.interceptingWindowInsetsListener = this idlingDetector.bindToLifecycle(this) - viewModel.onError.observe( + viewModel.onError.observeEvent( this, DialogErrorObserver( host = viewBinding.container, @@ -117,23 +119,23 @@ class ReaderActivity : onResolved = { isResolved -> if (isResolved) { viewModel.reload() - } else if (viewModel.content.value?.pages.isNullOrEmpty()) { + } else if (viewModel.content.value.pages.isEmpty()) { finishAfterTransition() } }, ), ) viewModel.readerMode.observe(this, this::onInitReader) - viewModel.onPageSaved.observe(this, this::onPageSaved) - viewModel.uiState.observeWithPrevious(this, this::onUiStateChanged) + viewModel.onPageSaved.observeEvent(this, this::onPageSaved) + viewModel.uiState.zipWithPrevious().observe(this, this::onUiStateChanged) viewModel.isLoading.observe(this, this::onLoadingStateChanged) viewModel.content.observe(this) { - onLoadingStateChanged(viewModel.isLoading.value == true) + onLoadingStateChanged(viewModel.isLoading.value) } viewModel.isScreenshotsBlockEnabled.observe(this, this::setWindowSecure) viewModel.isInfoBarEnabled.observe(this, ::onReaderBarChanged) viewModel.isBookmarkAdded.observe(this, this::onBookmarkStateChanged) - viewModel.onShowToast.observe(this) { msgId -> + viewModel.onShowToast.observeEvent(this) { msgId -> Snackbar.make(viewBinding.container, msgId, Snackbar.LENGTH_SHORT) .setAnchorView(viewBinding.appbarBottom) .show() @@ -150,7 +152,10 @@ class ReaderActivity : viewModel.saveCurrentState(readerManager.currentReader?.getCurrentState()) } - private fun onInitReader(mode: ReaderMode) { + private fun onInitReader(mode: ReaderMode?) { + if (mode == null) { + return + } if (readerManager.currentMode != mode) { readerManager.replace(mode) } @@ -190,7 +195,7 @@ class ReaderActivity : } R.id.action_bookmark -> { - if (viewModel.isBookmarkAdded.value == true) { + if (viewModel.isBookmarkAdded.value) { viewModel.removeBookmark() } else { viewModel.addBookmark() @@ -209,7 +214,7 @@ class ReaderActivity : } private fun onLoadingStateChanged(isLoading: Boolean) { - val hasPages = !viewModel.content.value?.pages.isNullOrEmpty() + val hasPages = viewModel.content.value.pages.isNotEmpty() viewBinding.layoutLoading.isVisible = isLoading && !hasPages if (isLoading && hasPages) { viewBinding.toastView.show(R.string.loading_) @@ -260,7 +265,7 @@ class ReaderActivity : override fun onPageSelected(page: ReaderPage) { lifecycleScope.launch(Dispatchers.Default) { - val pages = viewModel.content.value?.pages ?: return@launch + val pages = viewModel.content.value.pages val index = pages.indexOfFirst { it.chapterId == page.chapterId && it.id == page.id } if (index != -1) { withContext(Dispatchers.Main) { @@ -311,7 +316,7 @@ class ReaderActivity : TransitionManager.beginDelayedTransition(viewBinding.root, transition) viewBinding.appbarTop.isVisible = isUiVisible viewBinding.appbarBottom?.isVisible = isUiVisible - viewBinding.infoBar.isGone = isUiVisible || (viewModel.isInfoBarEnabled.value == false) + viewBinding.infoBar.isGone = isUiVisible || (!viewModel.isInfoBarEnabled.value) if (isUiVisible) { showSystemUI() } else { @@ -367,7 +372,8 @@ class ReaderActivity : menuItem.setIcon(if (isAdded) R.drawable.ic_bookmark_added else R.drawable.ic_bookmark) } - private fun onUiStateChanged(uiState: ReaderUiState?, previous: ReaderUiState?) { + private fun onUiStateChanged(pair: Pair) { + val (uiState: ReaderUiState?, previous: ReaderUiState?) = pair title = uiState?.chapterName ?: uiState?.mangaName ?: getString(R.string.loading_) viewBinding.infoBar.update(uiState) if (uiState == null) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index 029bf76b3..f32dbbbb6 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -5,8 +5,6 @@ import androidx.activity.result.ActivityResultLauncher import androidx.annotation.AnyThread import androidx.annotation.MainThread import androidx.annotation.WorkerThread -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -28,35 +26,32 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository -import org.koitharu.kotatsu.core.model.DoubleManga import org.koitharu.kotatsu.core.os.ShortcutsUpdater import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.parser.MangaIntent -import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.core.prefs.ScreenshotsPolicy import org.koitharu.kotatsu.core.prefs.observeAsFlow -import org.koitharu.kotatsu.core.prefs.observeAsLiveData +import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData -import org.koitharu.kotatsu.core.util.ext.emitValue -import org.koitharu.kotatsu.core.util.ext.processLifecycleScope +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.requireValue -import org.koitharu.kotatsu.history.domain.HistoryRepository -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE -import org.koitharu.kotatsu.local.domain.DoubleMangaLoader +import org.koitharu.kotatsu.details.domain.DoubleMangaLoadUseCase +import org.koitharu.kotatsu.details.domain.model.DoubleManga +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.history.data.PROGRESS_NONE +import org.koitharu.kotatsu.history.domain.HistoryUpdateUseCase import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaPage -import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.reader.domain.ChaptersLoader +import org.koitharu.kotatsu.reader.domain.DetectReaderModeUseCase import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState @@ -70,7 +65,6 @@ private const val PREFETCH_LIMIT = 10 @HiltViewModel class ReaderViewModel @Inject constructor( savedStateHandle: SavedStateHandle, - private val mangaRepositoryFactory: MangaRepository.Factory, private val dataRepository: MangaDataRepository, private val historyRepository: HistoryRepository, private val bookmarksRepository: BookmarksRepository, @@ -79,7 +73,9 @@ class ReaderViewModel @Inject constructor( private val pageLoader: PageLoader, private val chaptersLoader: ChaptersLoader, private val shortcutsUpdater: ShortcutsUpdater, - private val mangaLoader: DoubleMangaLoader, + private val doubleMangaLoadUseCase: DoubleMangaLoadUseCase, + private val historyUpdateUseCase: HistoryUpdateUseCase, + private val detectReaderModeUseCase: DetectReaderModeUseCase, ) : BaseViewModel() { private val intent = MangaIntent(savedStateHandle) @@ -95,29 +91,29 @@ class ReaderViewModel @Inject constructor( private val mangaFlow: Flow get() = mangaData.map { it?.any } - val readerMode = MutableLiveData() - val onPageSaved = SingleLiveEvent() - val onShowToast = SingleLiveEvent() - val uiState = MutableLiveData(null) + val readerMode = MutableStateFlow(null) + val onPageSaved = MutableEventFlow() + val onShowToast = MutableEventFlow() + val uiState = MutableStateFlow(null) - val content = MutableLiveData(ReaderContent(emptyList(), null)) + val content = MutableStateFlow(ReaderContent(emptyList(), null)) val manga: DoubleManga? get() = mangaData.value - val readerAnimation = settings.observeAsLiveData( - context = viewModelScope.coroutineContext + Dispatchers.Default, + val readerAnimation = settings.observeAsStateFlow( + scope = viewModelScope + Dispatchers.Default, key = AppSettings.KEY_READER_ANIMATION, valueProducer = { readerAnimation }, ) - val isInfoBarEnabled = settings.observeAsLiveData( - context = viewModelScope.coroutineContext + Dispatchers.Default, + val isInfoBarEnabled = settings.observeAsStateFlow( + scope = viewModelScope + Dispatchers.Default, key = AppSettings.KEY_READER_BAR, valueProducer = { isReaderBarEnabled }, ) - val isWebtoonZoomEnabled = settings.observeAsLiveData( - context = viewModelScope.coroutineContext + Dispatchers.Default, + val isWebtoonZoomEnabled = settings.observeAsStateFlow( + scope = viewModelScope + Dispatchers.Default, key = AppSettings.KEY_WEBTOON_ZOOM, valueProducer = { isWebtoonZoomEnable }, ) @@ -136,9 +132,9 @@ class ReaderViewModel @Inject constructor( ) { manga, policy -> policy == ScreenshotsPolicy.BLOCK_ALL || (policy == ScreenshotsPolicy.BLOCK_NSFW && manga != null && manga.isNsfw) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, false) - val isBookmarkAdded: LiveData = currentState.flatMapLatest { state -> + val isBookmarkAdded = currentState.flatMapLatest { state -> val manga = mangaData.value?.any if (state == null || manga == null) { flowOf(false) @@ -146,7 +142,7 @@ class ReaderViewModel @Inject constructor( bookmarksRepository.observeBookmark(manga, state.chapterId, state.page) .map { it != null } } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false) init { loadImpl() @@ -173,10 +169,8 @@ class ReaderViewModel @Inject constructor( mode = newMode, ) readerMode.value = newMode - content.value?.run { - content.value = copy( - state = getCurrentState(), - ) + content.update { + it.copy(state = getCurrentState()) } } } @@ -189,9 +183,9 @@ class ReaderViewModel @Inject constructor( return } val readerState = state ?: currentState.value ?: return - historyRepository.saveStateAsync( + historyUpdateUseCase.invokeAsync( manga = mangaData.value?.any ?: return, - state = readerState, + readerState = readerState, percent = computePercent(readerState.chapterId, readerState.page), ) } @@ -212,12 +206,12 @@ class ReaderViewModel @Inject constructor( prevJob?.cancelAndJoin() try { val dest = pageSaveHelper.savePage(pageLoader, page, saveLauncher) - onPageSaved.emitCall(dest) + onPageSaved.call(dest) } catch (e: CancellationException) { throw e } catch (e: Exception) { e.printStackTraceDebug() - onPageSaved.emitCall(null) + onPageSaved.call(null) } } } @@ -233,7 +227,7 @@ class ReaderViewModel @Inject constructor( fun getCurrentPage(): MangaPage? { val state = currentState.value ?: return null - return content.value?.pages?.find { + return content.value.pages.find { it.chapterId == state.chapterId && it.index == state.page }?.toMangaPage() } @@ -242,9 +236,9 @@ class ReaderViewModel @Inject constructor( val prevJob = loadingJob loadingJob = launchLoadingJob(Dispatchers.Default) { prevJob?.cancelAndJoin() - content.postValue(ReaderContent(emptyList(), null)) + content.value = ReaderContent(emptyList(), null) chaptersLoader.loadSingleChapter(id) - content.postValue(ReaderContent(chaptersLoader.snapshot(), ReaderState(id, page, 0))) + content.value = ReaderContent(chaptersLoader.snapshot(), ReaderState(id, page, 0)) } } @@ -254,7 +248,7 @@ class ReaderViewModel @Inject constructor( stateChangeJob = launchJob(Dispatchers.Default) { prevJob?.cancelAndJoin() loadingJob?.join() - val pages = content.value?.pages ?: return@launchJob + val pages = content.value.pages pages.getOrNull(position)?.let { page -> currentState.update { cs -> cs?.copy(chapterId = page.chapterId, page = page.index) @@ -296,7 +290,7 @@ class ReaderViewModel @Inject constructor( percent = computePercent(state.chapterId, state.page), ) bookmarksRepository.addBookmark(bookmark) - onShowToast.emitCall(R.string.bookmark_added) + onShowToast.call(R.string.bookmark_added) } } @@ -318,32 +312,31 @@ class ReaderViewModel @Inject constructor( var manga = DoubleManga(dataRepository.resolveIntent(intent) ?: throw NotFoundException("Cannot find manga", "")) mangaData.value = manga - manga = mangaLoader.load(intent) + manga = doubleMangaLoadUseCase(intent) chaptersLoader.init(manga) // determine mode val singleManga = manga.requireAny() - val mode = detectReaderMode(singleManga) // obtain state if (currentState.value == null) { currentState.value = historyRepository.getOne(singleManga)?.let { ReaderState(it) } ?: ReaderState(singleManga, preselectedBranch) } - + val mode = detectReaderModeUseCase.invoke(singleManga, currentState.value) val branch = chaptersLoader.peekChapter(currentState.value?.chapterId ?: 0L)?.branch mangaData.value = manga.filterChapters(branch) - readerMode.emitValue(mode) + readerMode.value = mode chaptersLoader.loadSingleChapter(requireNotNull(currentState.value).chapterId) // save state if (!isIncognito) { currentState.value?.let { val percent = computePercent(it.chapterId, it.page) - historyRepository.addOrUpdate(singleManga, it.chapterId, it.page, it.scroll, percent) + historyUpdateUseCase.invoke(singleManga, it, percent) } } notifyStateChanged() - content.emitValue(ReaderContent(chaptersLoader.snapshot(), currentState.value)) + content.value = ReaderContent(chaptersLoader.snapshot(), currentState.value) } } @@ -353,7 +346,7 @@ class ReaderViewModel @Inject constructor( loadingJob = launchLoadingJob(Dispatchers.Default) { prevJob?.join() chaptersLoader.loadPrevNextChapter(mangaData.requireValue(), currentId, isNext) - content.emitValue(ReaderContent(chaptersLoader.snapshot(), null)) + content.value = ReaderContent(chaptersLoader.snapshot(), null) } } @@ -367,27 +360,6 @@ class ReaderViewModel @Inject constructor( } } - private suspend fun detectReaderMode(manga: Manga): ReaderMode { - dataRepository.getReaderMode(manga.id)?.let { return it } - val defaultMode = settings.defaultReaderMode - if (!settings.isReaderModeDetectionEnabled || defaultMode == ReaderMode.WEBTOON) { - return defaultMode - } - val chapter = currentState.value?.chapterId?.let { chaptersLoader.peekChapter(it) } - ?: manga.chapters?.randomOrNull() - ?: error("There are no chapters in this manga") - val repo = mangaRepositoryFactory.create(manga.source) - val pages = repo.getPages(chapter) - return runCatchingCancellable { - val isWebtoon = dataRepository.determineMangaIsWebtoon(repo, pages) - if (isWebtoon) ReaderMode.WEBTOON else defaultMode - }.onSuccess { - dataRepository.saveReaderMode(manga, it) - }.onFailure { - it.printStackTraceDebug() - }.getOrDefault(defaultMode) - } - @WorkerThread private fun notifyStateChanged() { val state = getCurrentState() @@ -402,7 +374,7 @@ class ReaderViewModel @Inject constructor( isSliderEnabled = settings.isReaderSliderEnabled, percent = if (state != null) computePercent(state.chapterId, state.page) else PROGRESS_NONE, ) - uiState.postValue(newState) + uiState.value = newState } private fun computePercent(chapterId: Long, pageIndex: Int): Float { @@ -419,23 +391,3 @@ class ReaderViewModel @Inject constructor( return ppc * chapterIndex + ppc * pagePercent } } - -/** - * This function is not a member of the ReaderViewModel - * because it should work independently of the ViewModel's lifecycle. - */ -private fun HistoryRepository.saveStateAsync(manga: Manga, state: ReaderState, percent: Float): Job { - return processLifecycleScope.launch(Dispatchers.Default) { - runCatchingCancellable { - addOrUpdate( - manga = manga, - chapterId = state.chapterId, - page = state.page, - scroll = state.scroll, - percent = percent, - ) - }.onFailure { - it.printStackTraceDebug() - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigActivity.kt index 02a6b00ea..d77cdc62c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigActivity.kt @@ -24,6 +24,8 @@ import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.util.ext.decodeRegion import org.koitharu.kotatsu.core.util.ext.enqueueWith import org.koitharu.kotatsu.core.util.ext.indicator +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.setValueRounded import org.koitharu.kotatsu.databinding.ActivityColorFilterBinding import org.koitharu.kotatsu.parsers.model.Manga @@ -64,7 +66,7 @@ class ColorFilterConfigActivity : viewModel.colorFilter.observe(this, this::onColorFilterChanged) viewModel.isLoading.observe(this, this::onLoadingChanged) viewModel.preview.observe(this, this::onPreviewChanged) - viewModel.onDismiss.observe(this) { + viewModel.onDismiss.observeEvent(this) { finishAfterTransition() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigBackPressedDispatcher.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigBackPressedDispatcher.kt index a7d017c15..97527946c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigBackPressedDispatcher.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigBackPressedDispatcher.kt @@ -5,6 +5,7 @@ import android.content.DialogInterface import androidx.activity.OnBackPressedCallback import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.util.ext.call class ColorFilterConfigBackPressedDispatcher( private val context: Context, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigViewModel.kt index 22ef8497b..d4568ed2d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/colorfilter/ColorFilterConfigViewModel.kt @@ -1,16 +1,16 @@ package org.koitharu.kotatsu.reader.ui.colorfilter -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.model.parcelable.ParcelableMangaPages import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.ext.emitValue +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.reader.domain.ReaderColorFilter import org.koitharu.kotatsu.reader.ui.colorfilter.ColorFilterConfigActivity.Companion.EXTRA_MANGA @@ -26,9 +26,9 @@ class ColorFilterConfigViewModel @Inject constructor( private val manga = checkNotNull(savedStateHandle.get(EXTRA_MANGA)?.manga) private var initialColorFilter: ReaderColorFilter? = null - val colorFilter = MutableLiveData(null) - val onDismiss = SingleLiveEvent() - val preview = MutableLiveData(null) + val colorFilter = MutableStateFlow(null) + val onDismiss = MutableEventFlow() + val preview = MutableStateFlow(null) val isChanged: Boolean get() = colorFilter.value != initialColorFilter @@ -44,13 +44,11 @@ class ColorFilterConfigViewModel @Inject constructor( launchLoadingJob(Dispatchers.Default) { val repository = mangaRepositoryFactory.create(page.source) val url = repository.getPageUrl(page) - preview.emitValue( - MangaPage( - id = page.id, - url = url, - preview = page.preview, - source = page.source, - ), + preview.value = MangaPage( + id = page.id, + url = url, + preview = page.preview, + source = page.source, ) } } @@ -72,7 +70,7 @@ class ColorFilterConfigViewModel @Inject constructor( fun save() { launchLoadingJob(Dispatchers.Default) { mangaDataRepository.saveColorFilter(manga, colorFilter.value) - onDismiss.emitCall(Unit) + onDismiss.call(Unit) } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt index 714819f51..4fa2db3f8 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt @@ -18,12 +18,14 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ReaderMode -import org.koitharu.kotatsu.core.prefs.observeAsLiveData +import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.BaseBottomSheet import org.koitharu.kotatsu.core.util.ScreenOrientationHelper +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.SheetReaderConfigBinding @@ -75,8 +77,8 @@ class ReaderConfigBottomSheet : binding.sliderTimer.addOnChangeListener(this) binding.switchScrollTimer.setOnCheckedChangeListener(this) - settings.observeAsLiveData( - context = lifecycleScope.coroutineContext + Dispatchers.Default, + settings.observeAsStateFlow( + scope = lifecycleScope + Dispatchers.Default, key = AppSettings.KEY_READER_AUTOSCROLL_SPEED, valueProducer = { readerAutoscrollSpeed }, ).observe(viewLifecycleOwner) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BaseReaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BaseReaderFragment.kt index 7570a9f5c..e2a9a82e4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BaseReaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BaseReaderFragment.kt @@ -6,6 +6,7 @@ import androidx.fragment.app.activityViewModels import androidx.viewbinding.ViewBinding import org.koitharu.kotatsu.core.ui.BaseFragment import org.koitharu.kotatsu.core.util.ext.getParcelableCompat +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.reader.ui.ReaderState import org.koitharu.kotatsu.reader.ui.ReaderViewModel diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt index 016a7436f..ce228d578 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt @@ -10,6 +10,7 @@ import kotlinx.coroutines.launch import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.util.ext.doOnPageChanged import org.koitharu.kotatsu.core.util.ext.isAnimationsEnabled +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.recyclerView import org.koitharu.kotatsu.core.util.ext.resetTransformations import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt index 19815597b..c08199d24 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt @@ -10,6 +10,7 @@ import kotlinx.coroutines.launch import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.util.ext.doOnPageChanged import org.koitharu.kotatsu.core.util.ext.isAnimationsEnabled +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.recyclerView import org.koitharu.kotatsu.core.util.ext.resetTransformations import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt index b8f2eac37..e98d90c94 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt @@ -11,6 +11,7 @@ import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.util.ext.findCenterViewPosition import org.koitharu.kotatsu.core.util.ext.firstVisibleItemPosition import org.koitharu.kotatsu.core.util.ext.isAnimationsEnabled +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope import org.koitharu.kotatsu.databinding.FragmentReaderWebtoonBinding import org.koitharu.kotatsu.reader.domain.PageLoader diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt index b4fe13b2f..39255497c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt @@ -20,6 +20,8 @@ import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.ui.list.ScrollListenerInvalidationObserver import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.core.ui.widgets.BottomSheetHeaderBar +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.SheetPagesBinding @@ -93,7 +95,7 @@ class PagesThumbnailsSheet : viewModel.branch.observe(viewLifecycleOwner) { onExpansionStateChanged(binding.headerBar, binding.headerBar.isExpanded) } - viewModel.onError.observe(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) + viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) } override fun onDestroyView() { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt index 934245a5c..30e7ccb75 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt @@ -1,18 +1,17 @@ package org.koitharu.kotatsu.reader.ui.thumbnails -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.ext.emitValue +import org.koitharu.kotatsu.details.domain.DoubleMangaLoadUseCase import org.koitharu.kotatsu.list.ui.model.ListHeader import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingFooter -import org.koitharu.kotatsu.local.domain.DoubleMangaLoader import org.koitharu.kotatsu.parsers.util.SuspendLazy import org.koitharu.kotatsu.reader.domain.ChaptersLoader import javax.inject.Inject @@ -22,7 +21,7 @@ class PagesThumbnailsViewModel @Inject constructor( savedStateHandle: SavedStateHandle, mangaRepositoryFactory: MangaRepository.Factory, private val chaptersLoader: ChaptersLoader, - private val mangaLoader: DoubleMangaLoader, + private val doubleMangaLoadUseCase: DoubleMangaLoadUseCase, ) : BaseViewModel() { private val currentPageIndex: Int = savedStateHandle[PagesThumbnailsSheet.ARG_CURRENT_PAGE] ?: -1 @@ -31,9 +30,9 @@ class PagesThumbnailsViewModel @Inject constructor( private val repository = mangaRepositoryFactory.create(manga.source) private val mangaDetails = SuspendLazy { - mangaLoader.load(manga).let { + doubleMangaLoadUseCase(manga).let { val b = manga.chapters?.find { ch -> ch.id == initialChapterId }?.branch - branch.emitValue(b) + branch.value = b it.filterChapters(b) } } @@ -41,8 +40,8 @@ class PagesThumbnailsViewModel @Inject constructor( private var loadingPrevJob: Job? = null private var loadingNextJob: Job? = null - val thumbnails = MutableLiveData>() - val branch = MutableLiveData() + val thumbnails = MutableStateFlow>(emptyList()) + val branch = MutableStateFlow(null) val title = manga.title init { @@ -100,6 +99,6 @@ class PagesThumbnailsViewModel @Inject constructor( add(LoadingFooter(1)) } } - thumbnails.emitValue(pages) + thumbnails.value = pages } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt index a7a1fb73d..ee0890f4f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt @@ -1,6 +1,5 @@ package org.koitharu.kotatsu.remotelist.ui -import androidx.lifecycle.LiveData import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -9,11 +8,15 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.parser.MangaRepository @@ -21,7 +24,7 @@ import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.widgets.ChipsView -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.list.ui.MangaListViewModel @@ -65,12 +68,12 @@ class RemoteListViewModel @Inject constructor( private val listError = MutableStateFlow(null) private var loadingJob: Job? = null - val filterItems: LiveData> + val filterItems: StateFlow> get() = filter.items override val content = combine( mangaList, - listModeFlow, + listMode, createHeaderFlow(), listError, hasNextPage, @@ -90,7 +93,7 @@ class RemoteListViewModel @Inject constructor( } } } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) init { filter.observeState() @@ -163,7 +166,7 @@ class RemoteListViewModel @Inject constructor( e.printStackTraceDebug() listError.value = e if (!mangaList.value.isNullOrEmpty()) { - errorEvent.emitCall(e) + errorEvent.call(e) } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigActivity.kt index 4cc7c0963..f1a4fce2b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigActivity.kt @@ -19,6 +19,8 @@ import org.koitharu.kotatsu.core.ui.list.decor.TypedSpacingItemDecoration import org.koitharu.kotatsu.core.util.ext.disposeImageRequest import org.koitharu.kotatsu.core.util.ext.enqueueWith import org.koitharu.kotatsu.core.util.ext.newImageRequest +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.ActivityScrobblerConfigBinding import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService @@ -64,7 +66,7 @@ class ScrobblerConfigActivity : BaseActivity(), viewModel.content.observe(this, listAdapter::setItems) viewModel.user.observe(this, this::onUserChanged) viewModel.isLoading.observe(this, this::onLoadingStateChanged) - viewModel.onError.observe(this, SnackbarErrorObserver(viewBinding.recyclerView, null)) + viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.recyclerView, null)) viewModel.onLoggedOut.observe(this) { finishAfterTransition() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigViewModel.kt index 1096123eb..029d7ce1e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigViewModel.kt @@ -1,23 +1,24 @@ package org.koitharu.kotatsu.scrobbling.common.ui.config import android.net.Uri -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData -import org.koitharu.kotatsu.core.util.ext.emitValue +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.onFirst import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.list.ui.model.EmptyState @@ -40,34 +41,34 @@ class ScrobblerConfigViewModel @Inject constructor( val titleResId = scrobbler.scrobblerService.titleResId - val user = MutableLiveData(null) - val onLoggedOut = SingleLiveEvent() + val user = MutableStateFlow(null) + val onLoggedOut = MutableEventFlow() val content = scrobbler.observeAllScrobblingInfo() .onStart { loadingCounter.increment() } .onFirst { loadingCounter.decrement() } - .catch { errorEvent.postCall(it) } + .catch { errorEvent.call(it) } .map { buildContentList(it) } - .asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) + .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList()) init { scrobbler.user - .onEach { user.emitValue(it) } + .onEach { user.value = it } .launchIn(viewModelScope + Dispatchers.Default) } fun onAuthCodeReceived(authCode: String) { launchLoadingJob(Dispatchers.Default) { val newUser = scrobbler.authorize(authCode) - user.emitValue(newUser) + user.value = newUser } } fun logout() { launchLoadingJob(Dispatchers.Default) { scrobbler.logout() - user.emitValue(null) - onLoggedOut.emitCall(Unit) + user.value = null + onLoggedOut.call(Unit) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorBottomSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorBottomSheet.kt index 37502d42a..65e79be5e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorBottomSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorBottomSheet.kt @@ -22,6 +22,8 @@ import org.koitharu.kotatsu.core.ui.list.PaginationScrollListener import org.koitharu.kotatsu.core.ui.util.CollapseActionViewCallback import org.koitharu.kotatsu.core.util.ext.firstVisibleItemPosition import org.koitharu.kotatsu.core.util.ext.getDisplayMessage +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.SheetScrobblingSelectorBinding import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener @@ -72,8 +74,8 @@ class ScrobblingSelectorBottomSheet : decoration.checkedItemId = it binding.recyclerView.invalidateItemDecorations() } - viewModel.onError.observe(viewLifecycleOwner, ::onError) - viewModel.onClose.observe(viewLifecycleOwner) { + viewModel.onError.observeEvent(viewLifecycleOwner, ::onError) + viewModel.onClose.observeEvent(viewLifecycleOwner) { dismiss() } viewModel.selectedScrobblerIndex.observe(viewLifecycleOwner) { index -> diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorViewModel.kt index c27419e5d..f322f53c4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorViewModel.kt @@ -1,7 +1,5 @@ package org.koitharu.kotatsu.scrobbling.common.ui.selector -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import androidx.recyclerview.widget.RecyclerView.NO_ID @@ -9,14 +7,17 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.parser.MangaIntent import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData -import org.koitharu.kotatsu.core.util.ext.emitValue +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.core.util.ext.requireValue import org.koitharu.kotatsu.list.ui.model.ListModel @@ -39,7 +40,7 @@ class ScrobblingSelectorViewModel @Inject constructor( val availableScrobblers = scrobblers.filter { it.isAvailable } - val selectedScrobblerIndex = MutableLiveData(0) + val selectedScrobblerIndex = MutableStateFlow(0) private val scrobblerMangaList = MutableStateFlow>(emptyList()) private val hasNextPage = MutableStateFlow(true) @@ -51,7 +52,7 @@ class ScrobblingSelectorViewModel @Inject constructor( private val currentScrobbler: Scrobbler get() = availableScrobblers[selectedScrobblerIndex.requireValue()] - val content: LiveData> = combine( + val content: StateFlow> = combine( scrobblerMangaList, listError, hasNextPage, @@ -71,11 +72,11 @@ class ScrobblingSelectorViewModel @Inject constructor( }, ) } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) - val selectedItemId = MutableLiveData(NO_ID) - val searchQuery = MutableLiveData(manga.title) - val onClose = SingleLiveEvent() + val selectedItemId = MutableStateFlow(NO_ID) + val searchQuery = MutableStateFlow(manga.title) + val onClose = MutableEventFlow() val isEmpty: Boolean get() = scrobblerMangaList.value.isEmpty() @@ -130,13 +131,13 @@ class ScrobblingSelectorViewModel @Inject constructor( if (doneJob?.isActive == true) { return } - val targetId = selectedItemId.value ?: NO_ID + val targetId = selectedItemId.value if (targetId == NO_ID) { onClose.call(Unit) } doneJob = launchJob(Dispatchers.Default) { currentScrobbler.linkManga(manga.id, targetId) - onClose.emitCall(Unit) + onClose.call(Unit) } } @@ -155,7 +156,7 @@ class ScrobblingSelectorViewModel @Inject constructor( try { val info = currentScrobbler.getScrobblingInfoOrNull(manga.id) if (info != null) { - selectedItemId.emitValue(info.targetId) + selectedItemId.value = info.targetId } } finally { loadList(append = false) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchActivity.kt index f36639dec..cb89e0860 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchActivity.kt @@ -13,6 +13,7 @@ import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.showKeyboard import org.koitharu.kotatsu.databinding.ActivitySearchBinding import org.koitharu.kotatsu.parsers.model.MangaSource diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt index 7c442d0b1..ff7abf11c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt @@ -7,12 +7,14 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.core.util.asFlowLiveData import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.list.ui.MangaListViewModel @@ -44,7 +46,7 @@ class SearchViewModel @Inject constructor( override val content = combine( mangaList, - listModeFlow, + listMode, listError, hasNextPage, ) { list, mode, error, hasNext -> @@ -70,7 +72,7 @@ class SearchViewModel @Inject constructor( result } } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) init { loadList(append = false) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt index 0e0c59362..c8c75b2dd 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt @@ -21,6 +21,8 @@ import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.util.ShareHelper import org.koitharu.kotatsu.core.util.ext.invalidateNestedItemDecorations +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.databinding.ActivitySearchMultiBinding import org.koitharu.kotatsu.details.ui.DetailsActivity @@ -59,10 +61,8 @@ class MultiSearchActivity : setContentView(ActivitySearchMultiBinding.inflate(layoutInflater)) window.statusBarColor = ContextCompat.getColor(this, R.color.dim_statusbar) - val itemCLickListener = object : OnListItemClickListener { - override fun onItemClick(item: MultiSearchListModel, view: View) { - startActivity(SearchActivity.newIntent(view.context, item.source, viewModel.query.value)) - } + val itemCLickListener = OnListItemClickListener { item, view -> + startActivity(SearchActivity.newIntent(view.context, item.source, viewModel.query.value)) } val sizeResolver = ItemSizeResolver(resources, settings) val selectionDecoration = MangaSelectionDecoration(this) @@ -90,8 +90,8 @@ class MultiSearchActivity : viewModel.query.observe(this) { title = it } viewModel.list.observe(this) { adapter.items = it } - viewModel.onError.observe(this, SnackbarErrorObserver(viewBinding.recyclerView, null)) - viewModel.onDownloadStarted.observe(this, DownloadStartedObserver(viewBinding.recyclerView)) + viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.recyclerView, null)) + viewModel.onDownloadStarted.observeEvent(this, DownloadStartedObserver(viewBinding.recyclerView)) } override fun onWindowInsetsChanged(insets: Insets) { @@ -130,7 +130,7 @@ class MultiSearchActivity : } override fun onRetryClick(error: Throwable) { - viewModel.doSearch(viewModel.query.value.orEmpty()) + viewModel.doSearch(viewModel.query.value) } override fun onUpdateFilter(tags: Set) = Unit diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt index 1a420e11f..51a273537 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt @@ -1,7 +1,5 @@ package org.koitharu.kotatsu.search.ui.multi -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -12,17 +10,20 @@ import kotlinx.coroutines.async import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.CompositeException import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData -import org.koitharu.kotatsu.core.util.ext.emitValue +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel @@ -50,10 +51,10 @@ class MultiSearchViewModel @Inject constructor( private val listData = MutableStateFlow>(emptyList()) private val loadingData = MutableStateFlow(false) private var listError = MutableStateFlow(null) - val onDownloadStarted = SingleLiveEvent() + val onDownloadStarted = MutableEventFlow() - val query = MutableLiveData(savedStateHandle.get(MultiSearchActivity.EXTRA_QUERY).orEmpty()) - val list: LiveData> = combine( + val query = MutableStateFlow(savedStateHandle.get(MultiSearchActivity.EXTRA_QUERY).orEmpty()) + val list: StateFlow> = combine( listData, loadingData, listError, @@ -75,10 +76,10 @@ class MultiSearchViewModel @Inject constructor( loading -> list + LoadingFooter() else -> list } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) init { - doSearch(query.value.orEmpty()) + doSearch(query.value) } fun getItems(ids: Set): Set { @@ -101,7 +102,7 @@ class MultiSearchViewModel @Inject constructor( listError.value = null listData.value = emptyList() loadingData.value = true - query.emitValue(q) + query.value = q searchImpl(q) } catch (e: CancellationException) { throw e @@ -116,7 +117,7 @@ class MultiSearchViewModel @Inject constructor( fun download(items: Set) { launchJob(Dispatchers.Default) { downloadScheduler.schedule(items) - onDownloadStarted.emitCall(Unit) + onDownloadStarted.call(Unit) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionFragment.kt index bc77594e9..804e00f19 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionFragment.kt @@ -12,6 +12,7 @@ import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseFragment import org.koitharu.kotatsu.core.util.ext.addMenuProvider +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.databinding.FragmentSearchSuggestionBinding import org.koitharu.kotatsu.search.ui.suggestion.adapter.SearchSuggestionAdapter import javax.inject.Inject diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionViewModel.kt index 9862e195f..a01a2d31f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionViewModel.kt @@ -1,6 +1,5 @@ package org.koitharu.kotatsu.search.ui.suggestion -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers @@ -17,10 +16,9 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.plus import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.observeAsFlow -import org.koitharu.kotatsu.core.prefs.observeAsLiveData +import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.widgets.ChipsView -import org.koitharu.kotatsu.core.util.ext.emitValue import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.search.domain.MangaSearchRepository @@ -42,13 +40,13 @@ class SearchSuggestionViewModel @Inject constructor( private val query = MutableStateFlow("") private var suggestionJob: Job? = null - val isIncognitoModeEnabled = settings.observeAsLiveData( - context = viewModelScope.coroutineContext + Dispatchers.Default, + val isIncognitoModeEnabled = settings.observeAsStateFlow( + scope = viewModelScope + Dispatchers.Default, key = AppSettings.KEY_INCOGNITO_MODE, valueProducer = { isIncognitoModeEnabled }, ) - val suggestion = MutableLiveData>() + val suggestion = MutableStateFlow>(emptyList()) init { setupSuggestion() @@ -98,7 +96,7 @@ class SearchSuggestionViewModel @Inject constructor( buildSearchSuggestion(searchQuery, hiddenSources) }.distinctUntilChanged() .onEach { - suggestion.emitValue(it) + suggestion.value = it }.launchIn(viewModelScope + Dispatchers.Default) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsFragment.kt index 94051d98b..cda8c9fdd 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsFragment.kt @@ -18,6 +18,8 @@ import org.koitharu.kotatsu.core.logs.FileLogger import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BasePreferenceFragment import org.koitharu.kotatsu.core.util.ShareHelper +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import javax.inject.Inject @AndroidEntryPoint @@ -45,7 +47,7 @@ class AboutSettingsFragment : BasePreferenceFragment(R.string.about) { viewModel.isLoading.observe(viewLifecycleOwner) { findPreference(AppSettings.KEY_APP_UPDATE)?.isEnabled = !it } - viewModel.onUpdateAvailable.observe(viewLifecycleOwner, ::onUpdateAvailable) + viewModel.onUpdateAvailable.observeEvent(viewLifecycleOwner, ::onUpdateAvailable) } override fun onPreferenceTreeClick(preference: Preference): Boolean { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsViewModel.kt index 3ee1ea9e3..638ce1e8e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsViewModel.kt @@ -4,7 +4,8 @@ import dagger.hilt.android.lifecycle.HiltViewModel import org.koitharu.kotatsu.core.github.AppUpdateRepository import org.koitharu.kotatsu.core.github.AppVersion import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import javax.inject.Inject @HiltViewModel @@ -13,7 +14,7 @@ class AboutSettingsViewModel @Inject constructor( ) : BaseViewModel() { val isUpdateSupported = appUpdateRepository.isUpdateSupported() - val onUpdateAvailable = SingleLiveEvent() + val onUpdateAvailable = MutableEventFlow() fun checkForUpdates() { launchLoadingJob { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt index 19362ebb2..1a93c12d9 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt @@ -13,6 +13,8 @@ import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.AlertDialogFragment import org.koitharu.kotatsu.core.util.ext.getDisplayMessage +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.DialogProgressBinding import java.io.File import java.io.FileOutputStream @@ -46,8 +48,8 @@ class BackupDialogFragment : AlertDialogFragment() { binding.textViewSubtitle.setText(R.string.processing_) viewModel.progress.observe(viewLifecycleOwner, this::onProgressChanged) - viewModel.onBackupDone.observe(viewLifecycleOwner, this::onBackupDone) - viewModel.onError.observe(viewLifecycleOwner, this::onError) + viewModel.onBackupDone.observeEvent(viewLifecycleOwner, this::onBackupDone) + viewModel.onError.observeEvent(viewLifecycleOwner, this::onError) } override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupViewModel.kt index 80d9705e3..8c60b385f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupViewModel.kt @@ -1,13 +1,14 @@ package org.koitharu.kotatsu.settings.backup import android.content.Context -import androidx.lifecycle.MutableLiveData import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.MutableStateFlow import org.koitharu.kotatsu.core.backup.BackupRepository import org.koitharu.kotatsu.core.backup.BackupZipOutput import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import java.io.File import javax.inject.Inject @@ -17,8 +18,8 @@ class BackupViewModel @Inject constructor( @ApplicationContext context: Context, ) : BaseViewModel() { - val progress = MutableLiveData(-1f) - val onBackupDone = SingleLiveEvent() + val progress = MutableStateFlow(-1f) + val onBackupDone = MutableEventFlow() init { launchLoadingJob { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt index c1c7c7817..f2d0b200e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt @@ -12,6 +12,8 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.backup.CompositeResult import org.koitharu.kotatsu.core.ui.AlertDialogFragment import org.koitharu.kotatsu.core.util.ext.getDisplayMessage +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.DialogProgressBinding import kotlin.math.roundToInt @@ -32,8 +34,8 @@ class RestoreDialogFragment : AlertDialogFragment() { binding.textViewSubtitle.setText(R.string.preparing_) viewModel.progress.observe(viewLifecycleOwner, this::onProgressChanged) - viewModel.onRestoreDone.observe(viewLifecycleOwner, this::onRestoreDone) - viewModel.onError.observe(viewLifecycleOwner, this::onError) + viewModel.onRestoreDone.observeEvent(viewLifecycleOwner, this::onRestoreDone) + viewModel.onError.observeEvent(viewLifecycleOwner, this::onError) } override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt index cea8a7dfa..01b55c951 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt @@ -1,18 +1,19 @@ package org.koitharu.kotatsu.settings.backup import android.content.Context -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runInterruptible import org.koitharu.kotatsu.core.backup.BackupEntry import org.koitharu.kotatsu.core.backup.BackupRepository import org.koitharu.kotatsu.core.backup.BackupZipInput import org.koitharu.kotatsu.core.backup.CompositeResult import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.toUriOrNull import java.io.File import java.io.FileNotFoundException @@ -25,8 +26,8 @@ class RestoreViewModel @Inject constructor( @ApplicationContext context: Context, ) : BaseViewModel() { - val progress = MutableLiveData(-1f) - val onRestoreDone = SingleLiveEvent() + val progress = MutableStateFlow(-1f) + val onRestoreDone = MutableEventFlow() init { launchLoadingJob { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/newsources/NewSourcesDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/newsources/NewSourcesDialogFragment.kt index ac16391c6..bec4ad77f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/newsources/NewSourcesDialogFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/newsources/NewSourcesDialogFragment.kt @@ -11,6 +11,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.AlertDialogFragment +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.databinding.DialogOnboardBinding import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigListener import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/newsources/NewSourcesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/newsources/NewSourcesViewModel.kt index 3f631be7b..1a2a935a9 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/newsources/NewSourcesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/newsources/NewSourcesViewModel.kt @@ -1,8 +1,8 @@ package org.koitharu.kotatsu.settings.newsources import androidx.core.os.LocaleListCompat -import androidx.lifecycle.MutableLiveData import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow import org.koitharu.kotatsu.core.model.getLocaleTitle import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseViewModel @@ -15,13 +15,9 @@ class NewSourcesViewModel @Inject constructor( private val settings: AppSettings, ) : BaseViewModel() { - val sources = MutableLiveData>() + val sources = MutableStateFlow>(buildList()) private val initialList = settings.newSources - init { - buildList() - } - fun onItemEnabledChanged(item: SourceConfigItem.SourceItem, isEnabled: Boolean) { if (isEnabled) { settings.hiddenSources -= item.source.name @@ -34,10 +30,10 @@ class NewSourcesViewModel @Inject constructor( settings.markKnownSources(initialList) } - private fun buildList() { + private fun buildList(): List { val locales = LocaleListCompat.getDefault().mapToSet { it.language } val pendingHidden = HashSet() - sources.value = initialList.map { + return initialList.map { val locale = it.locale val isEnabledByLocale = locale == null || locale in locales if (!isEnabledByLocale) { @@ -49,9 +45,10 @@ class NewSourcesViewModel @Inject constructor( isEnabled = isEnabledByLocale, isDraggable = false, ) - } - if (pendingHidden.isNotEmpty()) { - settings.hiddenSources += pendingHidden + }.also { + if (pendingHidden.isNotEmpty()) { + settings.hiddenSources += pendingHidden + } } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt index 295a08a90..14ac39e54 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt @@ -10,6 +10,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.AlertDialogFragment +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.showAllowStateLoss import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.DialogOnboardBinding diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardViewModel.kt index 4380d0163..4707da3cc 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardViewModel.kt @@ -1,8 +1,8 @@ package org.koitharu.kotatsu.settings.onboard import androidx.core.os.LocaleListCompat -import androidx.lifecycle.MutableLiveData import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseViewModel @@ -26,7 +26,7 @@ class OnboardViewModel @Inject constructor( private val selectedLocales = locales.keys.toMutableSet() - val list = MutableLiveData?>() + val list = MutableStateFlow?>(null) init { if (settings.isSourcesSelected) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupActivity.kt index 955158643..88a1f64e4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupActivity.kt @@ -18,6 +18,7 @@ import androidx.core.view.isVisible import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseActivity +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.databinding.ActivitySetupProtectBinding private const val MIN_PASSWORD_LENGTH = 4 diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt index 387c34848..73b5597b3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt @@ -2,12 +2,16 @@ package org.koitharu.kotatsu.settings.protect import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.parsers.util.md5 import javax.inject.Inject @@ -20,10 +24,10 @@ class ProtectSetupViewModel @Inject constructor( val isSecondStep = firstPassword.map { it != null - }.asFlowLiveData(viewModelScope.coroutineContext, false) - val onPasswordSet = SingleLiveEvent() - val onPasswordMismatch = SingleLiveEvent() - val onClearText = SingleLiveEvent() + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, false) + val onPasswordSet = MutableEventFlow() + val onPasswordMismatch = MutableEventFlow() + val onClearText = MutableEventFlow() val isBiometricEnabled get() = settings.isBiometricProtectionEnabled diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt index d34733efa..12b20babc 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt @@ -21,6 +21,8 @@ import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver import org.koitharu.kotatsu.core.util.ext.addMenuProvider import org.koitharu.kotatsu.core.util.ext.getItem +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.FragmentSettingsSourcesBinding import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.settings.SettingsActivity @@ -64,7 +66,7 @@ class SourcesListFragment : viewModel.items.observe(viewLifecycleOwner) { sourcesAdapter.items = it } - viewModel.onActionDone.observe(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView)) + viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView)) addMenuProvider(SourcesMenuProvider()) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListViewModel.kt index 9eaf346c2..5ba8cd767 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListViewModel.kt @@ -1,10 +1,10 @@ package org.koitharu.kotatsu.settings.sources import androidx.core.os.LocaleListCompat -import androidx.lifecycle.MutableLiveData import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -14,11 +14,12 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.util.ReversibleAction import org.koitharu.kotatsu.core.ui.util.ReversibleHandle -import org.koitharu.kotatsu.core.util.SingleLiveEvent +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.map -import org.koitharu.kotatsu.core.util.ext.move import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.util.mapToSet +import org.koitharu.kotatsu.parsers.util.move import org.koitharu.kotatsu.parsers.util.toTitleCase import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem import java.util.Locale @@ -35,8 +36,8 @@ class SourcesListViewModel @Inject constructor( private val settings: AppSettings, ) : BaseViewModel() { - val items = MutableLiveData>(emptyList()) - val onActionDone = SingleLiveEvent() + val items = MutableStateFlow>(emptyList()) + val onActionDone = MutableEventFlow() private val mutex = Mutex() private val expandedGroups = HashSet() @@ -49,7 +50,7 @@ class SourcesListViewModel @Inject constructor( } fun reorderSources(oldPos: Int, newPos: Int): Boolean { - val snapshot = items.value?.toMutableList() ?: return false + val snapshot = items.value.toMutableList() if ((snapshot[oldPos] as? SourceConfigItem.SourceItem)?.isEnabled != true) return false if ((snapshot[newPos] as? SourceConfigItem.SourceItem)?.isEnabled != true) return false launchAtomicJob(Dispatchers.Default) { @@ -63,7 +64,7 @@ class SourcesListViewModel @Inject constructor( } fun canReorder(oldPos: Int, newPos: Int): Boolean { - val snapshot = items.value?.toMutableList() ?: return false + val snapshot = items.value.toMutableList() if ((snapshot[oldPos] as? SourceConfigItem.SourceItem)?.isEnabled != true) return false return (snapshot[newPos] as? SourceConfigItem.SourceItem)?.isEnabled == true } @@ -81,7 +82,7 @@ class SourcesListViewModel @Inject constructor( val rollback = ReversibleHandle { setEnabled(source, true) } - onActionDone.emitCall(ReversibleAction(R.string.source_disabled, rollback)) + onActionDone.call(ReversibleAction(R.string.source_disabled, rollback)) } buildList() } @@ -126,21 +127,19 @@ class SourcesListViewModel @Inject constructor( val hiddenSources = settings.hiddenSources val query = searchQuery if (!query.isNullOrEmpty()) { - items.postValue( - sources.mapNotNull { - if (!it.title.contains(query, ignoreCase = true)) { - return@mapNotNull null - } - SourceConfigItem.SourceItem( - source = it, - summary = it.getLocaleTitle(), - isEnabled = it.name !in hiddenSources, - isDraggable = false, - ) - }.ifEmpty { - listOf(SourceConfigItem.EmptySearchResult) - }, - ) + items.value = sources.mapNotNull { + if (!it.title.contains(query, ignoreCase = true)) { + return@mapNotNull null + } + SourceConfigItem.SourceItem( + source = it, + summary = it.getLocaleTitle(), + isEnabled = it.name !in hiddenSources, + isDraggable = false, + ) + }.ifEmpty { + listOf(SourceConfigItem.EmptySearchResult) + } return@runInterruptible } val map = sources.groupByTo(TreeMap(LocaleKeyComparator())) { @@ -188,7 +187,7 @@ class SourcesListViewModel @Inject constructor( } } } - items.postValue(result) + items.value = result } private fun getLocaleTitle(localeKey: String?): String? { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tools/ToolsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tools/ToolsFragment.kt index 51ea765ef..f0ecacc4d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tools/ToolsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tools/ToolsFragment.kt @@ -15,6 +15,7 @@ import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.github.AppVersion import org.koitharu.kotatsu.core.ui.BaseFragment +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.setChecked import org.koitharu.kotatsu.databinding.FragmentToolsBinding import org.koitharu.kotatsu.download.ui.list.DownloadsActivity diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tools/ToolsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tools/ToolsViewModel.kt index b977b7996..9d0289bb0 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tools/ToolsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tools/ToolsViewModel.kt @@ -1,14 +1,16 @@ package org.koitharu.kotatsu.settings.tools -import androidx.lifecycle.LiveData -import androidx.lifecycle.asLiveData -import androidx.lifecycle.liveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.core.github.AppUpdateRepository import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.core.prefs.observeAsLiveData +import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.local.data.CacheDir import org.koitharu.kotatsu.local.data.LocalStorageManager @@ -18,21 +20,18 @@ import javax.inject.Inject @HiltViewModel class ToolsViewModel @Inject constructor( private val storageManager: LocalStorageManager, - private val appUpdateRepository: AppUpdateRepository, private val settings: AppSettings, + appUpdateRepository: AppUpdateRepository, ) : BaseViewModel() { val appUpdate = appUpdateRepository.observeAvailableUpdate() - .asLiveData(viewModelScope.coroutineContext) - val storageUsage: LiveData = liveData( - context = viewModelScope.coroutineContext + Dispatchers.Default, - ) { + val storageUsage: StateFlow = flow { emit(collectStorageUsage()) - } + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null) - val isIncognitoModeEnabled = settings.observeAsLiveData( - context = viewModelScope.coroutineContext + Dispatchers.Default, + val isIncognitoModeEnabled = settings.observeAsStateFlow( + scope = viewModelScope + Dispatchers.Default, key = AppSettings.KEY_INCOGNITO_MODE, valueProducer = { isIncognitoModeEnabled }, ) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsFragment.kt index d60d185ad..51cca1a26 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsFragment.kt @@ -23,6 +23,7 @@ import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BasePreferenceFragment +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.settings.tracker.categories.TrackerCategoriesConfigSheet import org.koitharu.kotatsu.settings.utils.MultiSummaryProvider import org.koitharu.kotatsu.tracker.work.TrackerNotificationChannels diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsViewModel.kt index b6d0f8106..cd6713272 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/TrackerSettingsViewModel.kt @@ -1,15 +1,14 @@ package org.koitharu.kotatsu.settings.tracker -import androidx.lifecycle.MutableLiveData import androidx.room.InvalidationTracker import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow import okio.Closeable import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.TABLE_FAVOURITE_CATEGORIES import org.koitharu.kotatsu.core.db.removeObserverAsync import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.ext.emitValue import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject @@ -19,7 +18,7 @@ class TrackerSettingsViewModel @Inject constructor( private val database: MangaDatabase, ) : BaseViewModel() { - val categoriesCount = MutableLiveData(null) + val categoriesCount = MutableStateFlow(null) init { updateCategoriesCount() @@ -32,7 +31,7 @@ class TrackerSettingsViewModel @Inject constructor( private fun updateCategoriesCount() { launchJob(Dispatchers.Default) { - categoriesCount.emitValue(repository.getCategoriesCount()) + categoriesCount.value = repository.getCategoriesCount() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/categories/TrackerCategoriesConfigSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/categories/TrackerCategoriesConfigSheet.kt index 028a22020..942ef03ee 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/categories/TrackerCategoriesConfigSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/categories/TrackerCategoriesConfigSheet.kt @@ -12,6 +12,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.ui.BaseBottomSheet import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.databinding.SheetBaseBinding @AndroidEntryPoint diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/categories/TrackerCategoriesConfigViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/categories/TrackerCategoriesConfigViewModel.kt index 8ec72c44c..51daf79b1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/categories/TrackerCategoriesConfigViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/tracker/categories/TrackerCategoriesConfigViewModel.kt @@ -4,9 +4,11 @@ import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.asFlowLiveData import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import javax.inject.Inject @@ -16,7 +18,7 @@ class TrackerCategoriesConfigViewModel @Inject constructor( ) : BaseViewModel() { val content = favouritesRepository.observeCategories() - .asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) + .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList()) private var updateJob: Job? = null diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContentObserveUseCase.kt similarity index 74% rename from app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfRepository.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContentObserveUseCase.kt index a534c90cb..5fa916e1c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContentObserveUseCase.kt @@ -1,9 +1,5 @@ package org.koitharu.kotatsu.shelf.domain -import dagger.Reusable -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.combine @@ -18,19 +14,18 @@ import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity import org.koitharu.kotatsu.favourites.data.toFavouriteCategory import org.koitharu.kotatsu.favourites.data.toMangaList -import org.koitharu.kotatsu.history.domain.HistoryRepository -import org.koitharu.kotatsu.local.data.LocalManga +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.local.data.LocalMangaRepository import org.koitharu.kotatsu.local.data.LocalStorageChanges -import org.koitharu.kotatsu.local.domain.LocalMangaRepository +import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.SortOrder -import org.koitharu.kotatsu.parsers.util.runCatchingCancellable +import org.koitharu.kotatsu.shelf.domain.model.ShelfContent import org.koitharu.kotatsu.suggestions.domain.SuggestionRepository import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject -@Reusable -class ShelfRepository @Inject constructor( +class ShelfContentObserveUseCase @Inject constructor( private val localMangaRepository: LocalMangaRepository, private val historyRepository: HistoryRepository, private val trackingRepository: TrackingRepository, @@ -39,7 +34,7 @@ class ShelfRepository @Inject constructor( @LocalStorageChanges private val localStorageChanges: SharedFlow, ) { - fun observeShelfContent(): Flow = combine( + operator fun invoke(): Flow = combine( historyRepository.observeAllWithHistory(), observeLocalManga(SortOrder.UPDATED), observeFavourites(), @@ -69,23 +64,6 @@ class ShelfRepository @Inject constructor( } } - suspend fun deleteLocalManga(ids: Set) { - val list = localMangaRepository.getList(0, null, null) - .filter { x -> x.id in ids } - coroutineScope { - list.map { manga -> - async { - val original = localMangaRepository.getRemoteManga(manga) - if (localMangaRepository.delete(manga)) { - runCatchingCancellable { - historyRepository.deleteOrSwap(manga, original) - } - } - } - }.awaitAll() - } - } - private fun observeCategoriesContent( categories: List, ) = combine>, Map>>( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContent.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfContent.kt similarity index 89% rename from app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContent.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfContent.kt index 1319cf991..3e98c8cd3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContent.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfContent.kt @@ -1,7 +1,7 @@ -package org.koitharu.kotatsu.shelf.domain +package org.koitharu.kotatsu.shelf.domain.model import org.koitharu.kotatsu.core.model.FavouriteCategory -import org.koitharu.kotatsu.history.domain.MangaWithHistory +import org.koitharu.kotatsu.history.domain.model.MangaWithHistory import org.koitharu.kotatsu.parsers.model.Manga class ShelfContent( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfSection.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfSection.kt similarity index 62% rename from app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfSection.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfSection.kt index d798c09e5..ecdd14b7d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfSection.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfSection.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.shelf.domain +package org.koitharu.kotatsu.shelf.domain.model enum class ShelfSection { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfFragment.kt index cb499a611..50e2073af 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfFragment.kt @@ -21,6 +21,8 @@ import org.koitharu.kotatsu.core.ui.list.SectionedSelectionController import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver import org.koitharu.kotatsu.core.util.ext.addMenuProvider +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.FragmentShelfBinding import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver @@ -84,9 +86,9 @@ class ShelfFragment : addMenuProvider(ShelfMenuProvider(binding.root.context, childFragmentManager, viewModel)) viewModel.content.observe(viewLifecycleOwner, ::onListChanged) - viewModel.onError.observe(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) - viewModel.onActionDone.observe(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView)) - viewModel.onDownloadStarted.observe(viewLifecycleOwner, DownloadStartedObserver(binding.recyclerView)) + viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) + viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView)) + viewModel.onDownloadStarted.observeEvent(viewLifecycleOwner, DownloadStartedObserver(binding.recyclerView)) } override fun onSaveInstanceState(outState: Bundle) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt index e48113db3..557801d47 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt @@ -1,12 +1,15 @@ package org.koitharu.kotatsu.shelf.ui import androidx.collection.ArraySet -import androidx.lifecycle.LiveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.os.NetworkState @@ -15,13 +18,13 @@ import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.prefs.observeAsFlow import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.util.ReversibleAction -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.favourites.domain.FavouritesRepository -import org.koitharu.kotatsu.history.domain.HistoryRepository -import org.koitharu.kotatsu.history.domain.MangaWithHistory -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.history.data.PROGRESS_NONE +import org.koitharu.kotatsu.history.domain.model.MangaWithHistory import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.model.EmptyHint import org.koitharu.kotatsu.list.ui.model.EmptyState @@ -30,11 +33,12 @@ import org.koitharu.kotatsu.list.ui.model.LoadingState import org.koitharu.kotatsu.list.ui.model.toErrorState import org.koitharu.kotatsu.list.ui.model.toGridModel import org.koitharu.kotatsu.list.ui.model.toUi +import org.koitharu.kotatsu.local.domain.DeleteLocalMangaUseCase import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource -import org.koitharu.kotatsu.shelf.domain.ShelfContent -import org.koitharu.kotatsu.shelf.domain.ShelfRepository -import org.koitharu.kotatsu.shelf.domain.ShelfSection +import org.koitharu.kotatsu.shelf.domain.ShelfContentObserveUseCase +import org.koitharu.kotatsu.shelf.domain.model.ShelfContent +import org.koitharu.kotatsu.shelf.domain.model.ShelfSection import org.koitharu.kotatsu.shelf.ui.model.ShelfSectionModel import org.koitharu.kotatsu.sync.domain.SyncController import org.koitharu.kotatsu.tracker.domain.TrackingRepository @@ -42,30 +46,31 @@ import javax.inject.Inject @HiltViewModel class ShelfViewModel @Inject constructor( - private val repository: ShelfRepository, private val historyRepository: HistoryRepository, private val favouritesRepository: FavouritesRepository, private val trackingRepository: TrackingRepository, private val settings: AppSettings, private val downloadScheduler: DownloadWorker.Scheduler, + private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase, + shelfContentObserveUseCase: ShelfContentObserveUseCase, syncController: SyncController, networkState: NetworkState, ) : BaseViewModel(), ListExtraProvider { - val onActionDone = SingleLiveEvent() - val onDownloadStarted = SingleLiveEvent() + val onActionDone = MutableEventFlow() + val onDownloadStarted = MutableEventFlow() - val content: LiveData> = combine( + val content: StateFlow> = combine( settings.observeAsFlow(AppSettings.KEY_SHELF_SECTIONS) { shelfSections }, settings.observeAsFlow(AppSettings.KEY_TRACKER_ENABLED) { isTrackerEnabled }, settings.observeAsFlow(AppSettings.KEY_SUGGESTIONS) { isSuggestionsEnabled }, networkState, - repository.observeShelfContent(), + shelfContentObserveUseCase(), ) { sections, isTrackerEnabled, isSuggestionsEnabled, isConnected, content -> mapList(content, isTrackerEnabled, isSuggestionsEnabled, sections, isConnected) }.catch { e -> emit(listOf(e.toErrorState(canRetry = false))) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) init { launchJob(Dispatchers.Default) { @@ -95,7 +100,7 @@ class ShelfViewModel @Inject constructor( } launchJob(Dispatchers.Default) { val handle = favouritesRepository.removeFromCategory(category.id, ids) - onActionDone.emitCall(ReversibleAction(R.string.removed_from_favourites, handle)) + onActionDone.call(ReversibleAction(R.string.removed_from_favourites, handle)) } } @@ -105,14 +110,14 @@ class ShelfViewModel @Inject constructor( } launchJob(Dispatchers.Default) { val handle = historyRepository.delete(ids) - onActionDone.emitCall(ReversibleAction(R.string.removed_from_history, handle)) + onActionDone.call(ReversibleAction(R.string.removed_from_history, handle)) } } fun deleteLocal(ids: Set) { launchLoadingJob(Dispatchers.Default) { - repository.deleteLocalManga(ids) - onActionDone.emitCall(ReversibleAction(R.string.removal_completed, null)) + deleteLocalMangaUseCase(ids) + onActionDone.call(ReversibleAction(R.string.removal_completed, null)) } } @@ -125,12 +130,12 @@ class ShelfViewModel @Inject constructor( historyRepository.deleteAfter(minDate) R.string.removed_from_history } - onActionDone.emitCall(ReversibleAction(stringRes, null)) + onActionDone.call(ReversibleAction(stringRes, null)) } } fun getManga(ids: Set): Set { - val snapshot = content.value ?: return emptySet() + val snapshot = content.value val result = ArraySet(ids.size) for (section in snapshot) { if (section !is ShelfSectionModel) { @@ -151,7 +156,7 @@ class ShelfViewModel @Inject constructor( fun download(items: Set) { launchJob(Dispatchers.Default) { downloadScheduler.schedule(items) - onDownloadStarted.emitCall(Unit) + onDownloadStarted.call(Unit) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsActivity.kt index 6697d0367..e8c8f346f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsActivity.kt @@ -13,6 +13,7 @@ import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.core.ui.BaseActivity +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.databinding.ActivityShelfSettingsBinding import com.google.android.material.R as materialR @@ -40,8 +41,6 @@ class ShelfSettingsActivity : it.attachToRecyclerView(this) } } - - viewModel.content.observe(this) { settingsAdapter.items = it } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsAdapterDelegates.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsAdapterDelegates.kt index 2897e3eb6..736aa125f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsAdapterDelegates.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsAdapterDelegates.kt @@ -10,7 +10,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.util.ext.setChecked import org.koitharu.kotatsu.databinding.ItemCategoryCheckableMultipleBinding import org.koitharu.kotatsu.databinding.ItemShelfSectionDraggableBinding -import org.koitharu.kotatsu.shelf.domain.ShelfSection +import org.koitharu.kotatsu.shelf.domain.model.ShelfSection @SuppressLint("ClickableViewAccessibility") fun shelfSectionAD( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsItemModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsItemModel.kt index e75f329de..c45d6bee3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsItemModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsItemModel.kt @@ -1,7 +1,7 @@ package org.koitharu.kotatsu.shelf.ui.config import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.shelf.domain.ShelfSection +import org.koitharu.kotatsu.shelf.domain.model.ShelfSection sealed interface ShelfSettingsItemModel : ListModel { @@ -19,9 +19,7 @@ sealed interface ShelfSettingsItemModel : ListModel { other as Section if (section != other.section) return false - if (isChecked != other.isChecked) return false - - return true + return isChecked == other.isChecked } override fun hashCode(): Int { @@ -45,9 +43,7 @@ sealed interface ShelfSettingsItemModel : ListModel { if (id != other.id) return false if (title != other.title) return false - if (isChecked != other.isChecked) return false - - return true + return isChecked == other.isChecked } override fun hashCode(): Int { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsViewModel.kt index 6d9ac2bde..4df55a1d1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/config/ShelfSettingsViewModel.kt @@ -4,15 +4,17 @@ import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.observeAsFlow import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.asFlowLiveData import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.parsers.util.move -import org.koitharu.kotatsu.shelf.domain.ShelfSection +import org.koitharu.kotatsu.shelf.domain.model.ShelfSection import javax.inject.Inject @HiltViewModel @@ -27,7 +29,7 @@ class ShelfSettingsViewModel @Inject constructor( favouritesRepository.observeCategories(), ) { sections, isTrackerEnabled, categories -> buildList(sections, isTrackerEnabled, categories) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList()) private var updateJob: Job? = null @@ -57,7 +59,7 @@ class ShelfSettingsViewModel @Inject constructor( } fun reorderSections(oldPos: Int, newPos: Int): Boolean { - val snapshot = content.value?.toMutableList() ?: return false + val snapshot = content.value.toMutableList() snapshot.move(oldPos, newPos) settings.shelfSections = snapshot.sections() return true diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt index acf3fe5d1..5eff7818f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt @@ -3,13 +3,15 @@ package org.koitharu.kotatsu.suggestions.ui import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.core.util.asFlowLiveData import org.koitharu.kotatsu.core.util.ext.onFirst import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.list.ui.MangaListViewModel @@ -30,7 +32,7 @@ class SuggestionsViewModel @Inject constructor( override val content = combine( repository.observeAll(), - listModeFlow, + listMode, ) { list, mode -> when { list.isEmpty() -> listOf( @@ -50,10 +52,7 @@ class SuggestionsViewModel @Inject constructor( loadingCounter.decrement() }.catch { emit(listOf(it.toErrorState(canRetry = false))) - }.asFlowLiveData( - viewModelScope.coroutineContext + Dispatchers.Default, - listOf(LoadingState), - ) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) override fun onRefresh() = Unit diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt index e96b56930..e5770a597 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt @@ -46,7 +46,7 @@ import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull import org.koitharu.kotatsu.core.util.ext.trySetForeground import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.favourites.domain.FavouritesRepository -import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaTag diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt index 1ef83da4a..f26b3dd2d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt @@ -22,6 +22,8 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.getParcelableExtraCompat +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.ActivitySyncAuthBinding import org.koitharu.kotatsu.sync.data.SyncSettings import org.koitharu.kotatsu.sync.domain.SyncAuthResult @@ -52,8 +54,8 @@ class SyncAuthActivity : BaseActivity(), View.OnClickLi onBackPressedDispatcher.addCallback(pageBackCallback) - viewModel.onTokenObtained.observe(this, ::onTokenReceived) - viewModel.onError.observe(this, ::onError) + viewModel.onTokenObtained.observeEvent(this, ::onTokenReceived) + viewModel.onError.observeEvent(this, ::onError) viewModel.isLoading.observe(this, ::onLoadingStateChanged) viewModel.onAccountAlreadyExists.observe(this) { onAccountAlreadyExists() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthViewModel.kt index 6aea529a5..fd02134fa 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthViewModel.kt @@ -2,13 +2,14 @@ package org.koitharu.kotatsu.sync.ui import android.accounts.AccountManager import android.content.Context -import androidx.lifecycle.MutableLiveData import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.SingleLiveEvent +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty import org.koitharu.kotatsu.sync.data.SyncAuthApi import org.koitharu.kotatsu.sync.domain.SyncAuthResult @@ -20,9 +21,9 @@ class SyncAuthViewModel @Inject constructor( private val api: SyncAuthApi, ) : BaseViewModel() { - val onAccountAlreadyExists = SingleLiveEvent() - val onTokenObtained = SingleLiveEvent() - val host = MutableLiveData("") + val onAccountAlreadyExists = MutableEventFlow() + val onTokenObtained = MutableEventFlow() + val host = MutableStateFlow("") private val defaultHost = context.getString(R.string.sync_host_default) @@ -31,7 +32,7 @@ class SyncAuthViewModel @Inject constructor( val am = AccountManager.get(context) val accounts = am.getAccountsByType(context.getString(R.string.account_type_sync)) if (accounts.isNotEmpty()) { - onAccountAlreadyExists.emitCall(Unit) + onAccountAlreadyExists.call(Unit) } } } @@ -40,8 +41,8 @@ class SyncAuthViewModel @Inject constructor( val hostValue = host.value.ifNullOrEmpty { defaultHost } launchLoadingJob(Dispatchers.Default) { val token = api.authenticate(hostValue, email, password) - val result = SyncAuthResult(host.value.orEmpty(), email, password, token) - onTokenObtained.emitCall(result) + val result = SyncAuthResult(host.value, email, password, token) + onTokenObtained.call(result) } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/Tracker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/Tracker.kt index 31df0a6be..fcc8f996a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/Tracker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/Tracker.kt @@ -1,16 +1,16 @@ package org.koitharu.kotatsu.tracker.domain import androidx.annotation.VisibleForTesting -import javax.inject.Inject import org.koitharu.kotatsu.core.model.getPreferredBranch import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.tracker.domain.model.MangaTracking import org.koitharu.kotatsu.tracker.domain.model.MangaUpdates import org.koitharu.kotatsu.tracker.work.TrackerNotificationChannels import org.koitharu.kotatsu.tracker.work.TrackingItem +import javax.inject.Inject class Tracker @Inject constructor( private val settings: AppSettings, @@ -114,9 +114,11 @@ class Tracker @Inject constructor( newChapters.isEmpty() -> { MangaUpdates(manga, emptyList(), isValid = chapters.lastOrNull()?.id == track.lastChapterId) } + newChapters.size == chapters.size -> { MangaUpdates(manga, emptyList(), isValid = false) } + else -> { MangaUpdates(manga, newChapters, isValid = true) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt index b06b063be..2e9cfd162 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt @@ -18,6 +18,8 @@ import org.koitharu.kotatsu.core.ui.list.PaginationScrollListener import org.koitharu.kotatsu.core.ui.list.decor.TypedSpacingItemDecoration import org.koitharu.kotatsu.core.util.ext.addMenuProvider import org.koitharu.kotatsu.core.util.ext.getThemeColor +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.FragmentFeedBinding import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.list.ui.adapter.MangaListListener @@ -76,11 +78,11 @@ class FeedFragment : ) viewModel.content.observe(viewLifecycleOwner, this::onListChanged) - viewModel.onError.observe(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) + viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) viewModel.onFeedCleared.observe(viewLifecycleOwner) { onFeedCleared() } - TrackWorker.getIsRunningLiveData(binding.root.context.applicationContext) + TrackWorker.observeIsRunning(binding.root.context.applicationContext) .observe(viewLifecycleOwner, this::onIsTrackerRunningChanged) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt index 5c80f4a09..ce1c89b3a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt @@ -4,12 +4,15 @@ import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.model.DateTimeAgo -import org.koitharu.kotatsu.core.util.SingleLiveEvent -import org.koitharu.kotatsu.core.util.asFlowLiveData +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.daysDiff import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel @@ -32,7 +35,7 @@ class FeedViewModel @Inject constructor( private val limit = MutableStateFlow(PAGE_SIZE) private val isReady = AtomicBoolean(false) - val onFeedCleared = SingleLiveEvent() + val onFeedCleared = MutableEventFlow() val content = repository.observeTrackingLog(limit) .map { list -> if (list.isEmpty()) { @@ -48,7 +51,7 @@ class FeedViewModel @Inject constructor( isReady.set(true) list.mapList() } - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) fun clearFeed(clearCounters: Boolean) { launchLoadingJob(Dispatchers.Default) { @@ -56,7 +59,7 @@ class FeedViewModel @Inject constructor( if (clearCounters) { repository.clearCounters() } - onFeedCleared.emitCall(Unit) + onFeedCleared.call(Unit) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt index bb46a503f..a3dffc059 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt @@ -3,18 +3,20 @@ package org.koitharu.kotatsu.tracker.ui.updates import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ListMode -import org.koitharu.kotatsu.core.util.asFlowLiveData import org.koitharu.kotatsu.core.util.ext.onFirst import org.koitharu.kotatsu.download.ui.worker.DownloadWorker -import org.koitharu.kotatsu.history.domain.HistoryRepository -import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel @@ -38,7 +40,7 @@ class UpdatesViewModel @Inject constructor( override val content = combine( repository.observeUpdatedManga(), - listModeFlow, + listMode, ) { mangaMap, mode -> when { mangaMap.isEmpty() -> listOf( @@ -58,7 +60,7 @@ class UpdatesViewModel @Inject constructor( loadingCounter.decrement() }.catch { emit(listOf(it.toErrorState(canRetry = false))) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) override fun onRefresh() = Unit diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt index 06e8d25c7..934a19ac0 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt @@ -11,8 +11,7 @@ import androidx.core.app.NotificationCompat.VISIBILITY_SECRET import androidx.core.app.PendingIntentCompat import androidx.core.content.ContextCompat import androidx.hilt.work.HiltWorker -import androidx.lifecycle.LiveData -import androidx.lifecycle.map +import androidx.lifecycle.asFlow import androidx.work.BackoffPolicy import androidx.work.Constraints import androidx.work.CoroutineWorker @@ -35,6 +34,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.withContext import org.koitharu.kotatsu.R @@ -263,11 +264,13 @@ class TrackWorker @AssistedInject constructor( WorkManager.getInstance(context).enqueue(request) } - fun getIsRunningLiveData(context: Context): LiveData { + fun observeIsRunning(context: Context): Flow { val query = WorkQuery.Builder.fromTags(listOf(TAG, TAG_ONESHOT)).build() - return WorkManager.getInstance(context).getWorkInfosLiveData(query).map { works -> - works.any { x -> x.state == WorkInfo.State.RUNNING } - } + return WorkManager.getInstance(context).getWorkInfosLiveData(query) + .asFlow() + .map { works -> + works.any { x -> x.state == WorkInfo.State.RUNNING } + } } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentListFactory.kt b/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentListFactory.kt index fc263b5d7..83266be1e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentListFactory.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentListFactory.kt @@ -14,7 +14,7 @@ import kotlinx.coroutines.runBlocking import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaIntent import org.koitharu.kotatsu.core.util.ext.getDrawableOrThrow -import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.util.replaceWith diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentWidgetService.kt b/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentWidgetService.kt index 250892e28..a5052477a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentWidgetService.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentWidgetService.kt @@ -4,7 +4,7 @@ import android.content.Intent import android.widget.RemoteViewsService import coil.ImageLoader import dagger.hilt.android.AndroidEntryPoint -import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.history.data.HistoryRepository import javax.inject.Inject @AndroidEntryPoint diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfConfigActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfConfigActivity.kt index 15e453361..e51c3c912 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfConfigActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfConfigActivity.kt @@ -17,6 +17,8 @@ import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.prefs.AppWidgetConfig import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.ActivityCategoriesBinding import org.koitharu.kotatsu.widget.shelf.adapter.CategorySelectAdapter import org.koitharu.kotatsu.widget.shelf.model.CategoryItem @@ -57,7 +59,7 @@ class ShelfConfigActivity : viewModel.checkedId = config.categoryId viewModel.content.observe(this, this::onContentChanged) - viewModel.onError.observe(this, SnackbarErrorObserver(viewBinding.recyclerView, null)) + viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.recyclerView, null)) } override fun onClick(v: View) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt index 1208cb5dd..3a1b4deca 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt @@ -1,13 +1,15 @@ package org.koitharu.kotatsu.widget.shelf -import androidx.lifecycle.LiveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.util.asFlowLiveData import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.widget.shelf.model.CategoryItem import javax.inject.Inject @@ -19,7 +21,7 @@ class ShelfConfigViewModel @Inject constructor( private val selectedCategoryId = MutableStateFlow(0L) - val content: LiveData> = combine( + val content: StateFlow> = combine( favouritesRepository.observeCategories(), selectedCategoryId, ) { categories, selectedId -> @@ -29,7 +31,11 @@ class ShelfConfigViewModel @Inject constructor( CategoryItem(it.id, it.title, selectedId == it.id) } list - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList()) - var checkedId: Long by selectedCategoryId::value + var checkedId: Long + get() = selectedCategoryId.value + set(value) { + selectedCategoryId.value = value + } } From 6881c224538b6cdac4f3470a97d45916569289cf Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 27 May 2023 17:38:32 +0300 Subject: [PATCH 09/94] Update parsers --- app/build.gradle | 12 ++++++------ .../org/koitharu/kotatsu/core/parser/DummyParser.kt | 2 +- .../koitharu/kotatsu/settings/SourceSettingsExt.kt | 10 ++++++++-- .../org/koitharu/kotatsu/core/parser/DummyParser.kt | 2 +- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 24a9609d1..11d1f3d2e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdkVersion 21 targetSdkVersion 33 - versionCode 546 - versionName '5.1.2' + versionCode 547 + versionName '5.1.3' generatedDensities = [] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -78,7 +78,7 @@ afterEvaluate { } dependencies { //noinspection GradleDependency - implementation('com.github.KotatsuApp:kotatsu-parsers:ebcc6391d6') { + implementation('com.github.KotatsuApp:kotatsu-parsers:fa7ea5b16a') { exclude group: 'org.json', module: 'json' } @@ -87,7 +87,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.core:core-ktx:1.10.1' - implementation 'androidx.activity:activity-ktx:1.7.1' + implementation 'androidx.activity:activity-ktx:1.7.2' implementation 'androidx.fragment:fragment-ktx:1.5.7' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1' @@ -96,7 +96,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'androidx.recyclerview:recyclerview:1.3.0' - implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01' + implementation 'androidx.viewpager2:viewpager2:1.1.0-beta02' implementation 'androidx.preference:preference-ktx:1.2.0' implementation 'androidx.biometric:biometric-ktx:1.2.0-alpha05' implementation 'com.google.android.material:material:1.9.0' @@ -136,7 +136,7 @@ dependencies { implementation 'ch.acra:acra-http:5.9.7' implementation 'ch.acra:acra-dialog:5.9.7' - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10' + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.11' testImplementation 'junit:junit:4.13.2' testImplementation 'org.json:json:20230227' diff --git a/app/src/debug/java/org/koitharu/kotatsu/core/parser/DummyParser.kt b/app/src/debug/java/org/koitharu/kotatsu/core/parser/DummyParser.kt index a60655a2a..fb96f6e64 100644 --- a/app/src/debug/java/org/koitharu/kotatsu/core/parser/DummyParser.kt +++ b/app/src/debug/java/org/koitharu/kotatsu/core/parser/DummyParser.kt @@ -17,7 +17,7 @@ import java.util.EnumSet class DummyParser(context: MangaLoaderContext) : MangaParser(context, MangaSource.DUMMY) { override val configKeyDomain: ConfigKey.Domain - get() = ConfigKey.Domain("", null) + get() = ConfigKey.Domain() override val sortOrders: Set get() = EnumSet.allOf(SortOrder::class.java) diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsExt.kt b/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsExt.kt index 293f4847d..6a83af617 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsExt.kt @@ -19,10 +19,12 @@ fun PreferenceFragmentCompat.addPreferencesFromRepository(repository: RemoteMang val preference: Preference = when (key) { is ConfigKey.Domain -> { val presetValues = key.presetValues - if (presetValues.isNullOrEmpty()) { + if (presetValues.size <= 1) { EditTextPreference(requireContext()) } else { - AutoCompleteTextViewPreference(requireContext()).apply { entries = presetValues } + AutoCompleteTextViewPreference(requireContext()).apply { + entries = presetValues.toStringArray() + } }.apply { summaryProvider = EditTextDefaultSummaryProvider(key.defaultValue) setOnBindEditTextListener( @@ -64,3 +66,7 @@ fun PreferenceFragmentCompat.addPreferencesFromRepository(repository: RemoteMang screen.addPreference(preference) } } + +private fun Array.toStringArray(): Array { + return Array(size) { i -> this[i] as? String ?: "" } +} diff --git a/app/src/release/java/org/koitharu/kotatsu/core/parser/DummyParser.kt b/app/src/release/java/org/koitharu/kotatsu/core/parser/DummyParser.kt index 12722988c..030cb28de 100644 --- a/app/src/release/java/org/koitharu/kotatsu/core/parser/DummyParser.kt +++ b/app/src/release/java/org/koitharu/kotatsu/core/parser/DummyParser.kt @@ -15,7 +15,7 @@ import java.util.EnumSet class DummyParser(context: MangaLoaderContext) : MangaParser(context, MangaSource.DUMMY) { override val configKeyDomain: ConfigKey.Domain - get() = ConfigKey.Domain("localhost", null) + get() = ConfigKey.Domain("localhost") override val sortOrders: Set get() = EnumSet.allOf(SortOrder::class.java) From 2442e7cbe14fe3d6975d84454a3fe2de46614843 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 29 May 2023 13:06:50 +0300 Subject: [PATCH 10/94] Fix warnings --- app/build.gradle | 10 ++--- .../core/parser/RemoteMangaRepository.kt | 2 +- .../core/parser/favicon/FaviconFetcher.kt | 6 +-- .../kotatsu/core/ui/BaseFullscreenActivity.kt | 38 ++++--------------- .../org/koitharu/kotatsu/core/util/Event.kt | 2 +- .../koitharu/kotatsu/core/util/ext/Android.kt | 2 + .../kotatsu/core/util/ext/FlowObserver.kt | 4 -- .../kotatsu/explore/ui/ExploreFragment.kt | 2 +- .../kotatsu/explore/ui/model/ExploreItem.kt | 13 ++----- .../local/data/input/LocalMangaDirInput.kt | 1 - .../koitharu/kotatsu/main/ui/MainActivity.kt | 2 +- .../kotatsu/main/ui/MainNavigationDelegate.kt | 3 +- .../ui/config/ScrobblerConfigActivity.kt | 2 +- .../settings/protect/ProtectSetupActivity.kt | 7 ++-- .../kotatsu/sync/ui/SyncAuthActivity.kt | 2 +- .../kotatsu/tracker/ui/feed/FeedFragment.kt | 2 +- build.gradle | 2 +- 17 files changed, 34 insertions(+), 66 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9ee4d3fd9..5e3d86120 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -106,7 +106,7 @@ dependencies { implementation 'androidx.work:work-runtime-ktx:2.8.1' //noinspection GradleDependency - implementation('com.google.guava:guava:31.1-android') { + implementation('com.google.guava:guava:32.0.0-android') { exclude group: 'com.google.guava', module: 'failureaccess' exclude group: 'org.checkerframework', module: 'checker-qual' exclude group: 'com.google.j2objc', module: 'j2objc-annotations' @@ -116,8 +116,8 @@ dependencies { implementation 'androidx.room:room-ktx:2.5.1' kapt 'androidx.room:room-compiler:2.5.1' - implementation 'com.squareup.okhttp3:okhttp:4.10.0' - implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.3' + implementation 'com.squareup.okhttp3:okhttp:4.11.0' + implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.11.0' implementation 'com.squareup.okio:okio:3.3.0' implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl:4.3.2' @@ -128,8 +128,8 @@ dependencies { implementation 'androidx.hilt:hilt-work:1.0.0' kapt 'androidx.hilt:hilt-compiler:1.0.0' - implementation 'io.coil-kt:coil-base:2.3.0' - implementation 'io.coil-kt:coil-svg:2.3.0' + implementation 'io.coil-kt:coil-base:2.4.0' + implementation 'io.coil-kt:coil-svg:2.4.0' implementation 'com.github.KotatsuApp:subsampling-scale-image-view:1b19231b2f' implementation 'com.github.solkin:disk-lru-cache:1.4' implementation 'io.noties.markwon:core:4.6.2' diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt index 0f3d6d482..65758fd99 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt @@ -101,7 +101,7 @@ class RemoteMangaRepository( } fun getAvailableMirrors(): List { - return parser.configKeyDomain.presetValues?.toList().orEmpty() + return parser.configKeyDomain.presetValues.toList() } private fun getConfig() = parser.config as SourceSettings diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/favicon/FaviconFetcher.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/favicon/FaviconFetcher.kt index be0d0dcfc..6af4218ae 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/favicon/FaviconFetcher.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/favicon/FaviconFetcher.kt @@ -86,7 +86,7 @@ class FaviconFetcher( if (!options.diskCachePolicy.readEnabled) { return null } - val snapshot = diskCache.value?.get(diskCacheKey) ?: return null + val snapshot = diskCache.value?.openSnapshot(diskCacheKey) ?: return null return SourceResult( source = snapshot.toImageSource(), mimeType = null, @@ -98,12 +98,12 @@ class FaviconFetcher( if (!options.diskCachePolicy.writeEnabled || body.contentLength() == 0L) { return null } - val editor = diskCache.value?.edit(diskCacheKey) ?: return null + val editor = diskCache.value?.openEditor(diskCacheKey) ?: return null try { fileSystem.write(editor.data) { body.source().readAll(this) } - return editor.commitAndGet() + return editor.commitAndOpenSnapshot() } catch (e: Throwable) { try { editor.abort() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseFullscreenActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseFullscreenActivity.kt index 96a240e55..27f2b5fb2 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseFullscreenActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseFullscreenActivity.kt @@ -3,57 +3,35 @@ package org.koitharu.kotatsu.core.ui import android.graphics.Color import android.os.Build import android.os.Bundle -import android.view.View import android.view.WindowManager +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat import androidx.viewbinding.ViewBinding -@Suppress("DEPRECATION") -private const val SYSTEM_UI_FLAGS_SHOWN = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - -@Suppress("DEPRECATION") -private const val SYSTEM_UI_FLAGS_HIDDEN = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or - View.SYSTEM_UI_FLAG_FULLSCREEN or - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - abstract class BaseFullscreenActivity : - BaseActivity(), - View.OnSystemUiVisibilityChangeListener { + BaseActivity() { + + private lateinit var insetsControllerCompat: WindowInsetsControllerCompat override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) with(window) { + insetsControllerCompat = WindowInsetsControllerCompat(this, decorView) statusBarColor = Color.TRANSPARENT navigationBarColor = Color.TRANSPARENT if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES } - decorView.setOnSystemUiVisibilityChangeListener(this@BaseFullscreenActivity) } showSystemUI() } - @Suppress("DEPRECATION", "DeprecatedCallableAddReplaceWith") - @Deprecated("Deprecated in Java") - final override fun onSystemUiVisibilityChange(visibility: Int) { - onSystemUiVisibilityChanged(visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) - } - - // TODO WindowInsetsControllerCompat works incorrect - @Suppress("DEPRECATION") protected fun hideSystemUI() { - window.decorView.systemUiVisibility = SYSTEM_UI_FLAGS_HIDDEN + insetsControllerCompat.hide(WindowInsetsCompat.Type.systemBars()) } - @Suppress("DEPRECATION") protected fun showSystemUI() { - window.decorView.systemUiVisibility = SYSTEM_UI_FLAGS_SHOWN + insetsControllerCompat.show(WindowInsetsCompat.Type.systemBars()) } - - protected open fun onSystemUiVisibilityChanged(isVisible: Boolean) = Unit } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/Event.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/Event.kt index e14d2703c..1fd768af1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/Event.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/Event.kt @@ -8,7 +8,7 @@ class Event( private var isConsumed = false suspend fun consume(collector: FlowCollector) { - if (isConsumed) { + if (!isConsumed) { collector.emit(data) isConsumed = true } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt index 02c0f3ba0..9f5941449 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt @@ -23,6 +23,8 @@ import android.widget.Toast import androidx.activity.result.ActivityResultLauncher import androidx.annotation.IntegerRes import androidx.core.app.ActivityOptionsCompat +import androidx.core.content.IntentCompat +import androidx.core.content.PackageManagerCompat import androidx.core.os.LocaleListCompat import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/FlowObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/FlowObserver.kt index bfd2db25f..e13f221e1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/FlowObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/FlowObserver.kt @@ -9,13 +9,9 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch -import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.core.util.Event fun Flow.observe(owner: LifecycleOwner, collector: FlowCollector) { - if (BuildConfig.DEBUG) { - require((this as? StateFlow)?.value !is Event<*>) - } val start = if (this is StateFlow) CoroutineStart.UNDISPATCHED else CoroutineStart.DEFAULT owner.lifecycleScope.launch(start = start) { owner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt index 69b6c9d5c..bf58733d5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt @@ -80,7 +80,7 @@ class ExploreFragment : viewModel.onOpenManga.observeEvent(viewLifecycleOwner, ::onOpenManga) viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView)) viewModel.isGrid.observe(viewLifecycleOwner, ::onGridModeChanged) - viewModel.onShowSuggestionsTip.observe(viewLifecycleOwner) { + viewModel.onShowSuggestionsTip.observeEvent(viewLifecycleOwner) { showSuggestionsTip() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/model/ExploreItem.kt b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/model/ExploreItem.kt index e9d4603f3..9449ee21a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/model/ExploreItem.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/model/ExploreItem.kt @@ -18,9 +18,7 @@ sealed interface ExploreItem : ListModel { other as Buttons - if (isSuggestionsEnabled != other.isSuggestionsEnabled) return false - - return true + return isSuggestionsEnabled == other.isSuggestionsEnabled } override fun hashCode(): Int { @@ -40,9 +38,7 @@ sealed interface ExploreItem : ListModel { other as Header if (titleResId != other.titleResId) return false - if (isButtonVisible != other.isButtonVisible) return false - - return true + return isButtonVisible == other.isButtonVisible } override fun hashCode(): Int { @@ -64,9 +60,7 @@ sealed interface ExploreItem : ListModel { other as Source if (source != other.source) return false - if (isGrid != other.isGrid) return false - - return true + return isGrid == other.isGrid } override fun hashCode(): Int { @@ -76,7 +70,6 @@ sealed interface ExploreItem : ListModel { } } - @Deprecated("") class EmptyHint( @DrawableRes icon: Int, @StringRes textPrimary: Int, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt index e62943d07..c2cac2c60 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt @@ -130,7 +130,6 @@ class LocalMangaDirInput(root: File) : LocalMangaInput(root) { } val cbz = root.listFilesRecursive(CbzFilter()).firstOrNull() ?: return null return ZipFile(cbz).use { zip -> - val filter = ImageFileFilter() zip.entries().asSequence() .firstOrNull { x -> !x.isDirectory && filter.accept(x) } ?.let { entry -> zipUri(cbz, entry.name) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt index 024cb6994..731aa12de 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt @@ -129,7 +129,7 @@ class MainActivity : navigationDelegate = MainNavigationDelegate(checkNotNull(bottomNav ?: viewBinding.navRail), supportFragmentManager) navigationDelegate.addOnFragmentChangedListener(this) - navigationDelegate.onCreate(savedInstanceState) + navigationDelegate.onCreate() onBackPressedDispatcher.addCallback(ExitCallback(this, viewBinding.container)) onBackPressedDispatcher.addCallback(navigationDelegate) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainNavigationDelegate.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainNavigationDelegate.kt index fe23e3cc2..adfec639a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainNavigationDelegate.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainNavigationDelegate.kt @@ -1,6 +1,5 @@ package org.koitharu.kotatsu.main.ui -import android.os.Bundle import android.view.MenuItem import androidx.activity.OnBackPressedCallback import androidx.annotation.IdRes @@ -57,7 +56,7 @@ class MainNavigationDelegate( navBar.selectedItemId = R.id.nav_shelf } - fun onCreate(savedInstanceState: Bundle?) { + fun onCreate() { primaryFragment?.let { onFragmentChanged(it, fromUser = false) val itemId = getItemId(it) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigActivity.kt index f1a4fce2b..ac1784635 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigActivity.kt @@ -67,7 +67,7 @@ class ScrobblerConfigActivity : BaseActivity(), viewModel.user.observe(this, this::onUserChanged) viewModel.isLoading.observe(this, this::onLoadingStateChanged) viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.recyclerView, null)) - viewModel.onLoggedOut.observe(this) { + viewModel.onLoggedOut.observeEvent(this) { finishAfterTransition() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupActivity.kt index 88a1f64e4..cc086c8cd 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupActivity.kt @@ -19,6 +19,7 @@ import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.ActivitySetupProtectBinding private const val MIN_PASSWORD_LENGTH = 4 @@ -46,13 +47,13 @@ class ProtectSetupActivity : viewBinding.switchBiometric.setOnCheckedChangeListener(this) viewModel.isSecondStep.observe(this, this::onStepChanged) - viewModel.onPasswordSet.observe(this) { + viewModel.onPasswordSet.observeEvent(this) { finishAfterTransition() } - viewModel.onPasswordMismatch.observe(this) { + viewModel.onPasswordMismatch.observeEvent(this) { viewBinding.editPassword.error = getString(R.string.passwords_mismatch) } - viewModel.onClearText.observe(this) { + viewModel.onClearText.observeEvent(this) { viewBinding.editPassword.text?.clear() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt index f26b3dd2d..a7cd65491 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncAuthActivity.kt @@ -57,7 +57,7 @@ class SyncAuthActivity : BaseActivity(), View.OnClickLi viewModel.onTokenObtained.observeEvent(this, ::onTokenReceived) viewModel.onError.observeEvent(this, ::onError) viewModel.isLoading.observe(this, ::onLoadingStateChanged) - viewModel.onAccountAlreadyExists.observe(this) { + viewModel.onAccountAlreadyExists.observeEvent(this) { onAccountAlreadyExists() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt index 2e9cfd162..588e22677 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt @@ -79,7 +79,7 @@ class FeedFragment : viewModel.content.observe(viewLifecycleOwner, this::onListChanged) viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) - viewModel.onFeedCleared.observe(viewLifecycleOwner) { + viewModel.onFeedCleared.observeEvent(viewLifecycleOwner) { onFeedCleared() } TrackWorker.observeIsRunning(binding.root.context.applicationContext) diff --git a/build.gradle b/build.gradle index c420893c0..bd956dc1e 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.0.1' + classpath 'com.android.tools.build:gradle:8.0.2' classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.21' classpath 'com.google.dagger:hilt-android-gradle-plugin:2.46.1' } From 3d05541f61d64527de3158e46709c3a1b008ab9b Mon Sep 17 00:00:00 2001 From: Koitharu Date: Tue, 30 May 2023 08:49:21 +0300 Subject: [PATCH 11/94] Update reader activity ui --- .../kotatsu/core/ui/BaseFullscreenActivity.kt | 1 + .../list/fastscroll/FastScrollRecyclerView.kt | 9 ++- .../kotatsu/reader/ui/ReaderActivity.kt | 22 ++++--- .../kotatsu/reader/ui/ReaderViewModel.kt | 1 + .../ui/config/ReaderConfigBottomSheet.kt | 3 +- .../kotatsu/reader/ui/pager/ReaderUiState.kt | 10 ++++ .../ui/thumbnails/PagesThumbnailsSheet.kt | 1 + .../adapter/PageThumbnailAdapter.kt | 15 ++++- .../tracker/ui/feed/adapter/FeedAdapter.kt | 15 ++++- .../res/layout-w600dp/activity_reader.xml | 44 +++++++------- .../res/layout-w600dp/fragment_details.xml | 1 + app/src/main/res/layout/activity_browser.xml | 3 +- app/src/main/res/layout/activity_reader.xml | 58 +++++++++---------- app/src/main/res/layout/fragment_details.xml | 1 + app/src/main/res/layout/item_download.xml | 1 - app/src/main/res/layout/sheet_pages.xml | 26 +++++---- app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 8 +++ app/src/main/res/values/themes.xml | 2 + 19 files changed, 142 insertions(+), 80 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseFullscreenActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseFullscreenActivity.kt index 27f2b5fb2..9a7ccbd2e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseFullscreenActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseFullscreenActivity.kt @@ -24,6 +24,7 @@ abstract class BaseFullscreenActivity : WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES } } + insetsControllerCompat.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE showSystemUI() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/fastscroll/FastScrollRecyclerView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/fastscroll/FastScrollRecyclerView.kt index 2b62a6d49..1a1590019 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/fastscroll/FastScrollRecyclerView.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/fastscroll/FastScrollRecyclerView.kt @@ -4,6 +4,7 @@ import android.content.Context import android.util.AttributeSet import android.view.ViewGroup import androidx.annotation.AttrRes +import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView import org.koitharu.kotatsu.R @@ -15,6 +16,12 @@ class FastScrollRecyclerView @JvmOverloads constructor( val fastScroller = FastScroller(context, attrs) + var isFastScrollerEnabled: Boolean = true + set(value) { + field = value + fastScroller.isVisible = value && isVisible + } + init { fastScroller.id = R.id.fast_scroller fastScroller.layoutParams = ViewGroup.LayoutParams( @@ -30,7 +37,7 @@ class FastScrollRecyclerView @JvmOverloads constructor( override fun setVisibility(visibility: Int) { super.setVisibility(visibility) - fastScroller.visibility = visibility + fastScroller.visibility = if (isFastScrollerEnabled) visibility else GONE } override fun onAttachedToWindow() { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index f3f655ede..0b8ce9908 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -14,6 +14,7 @@ import android.view.Menu import android.view.MenuItem import android.view.MotionEvent import android.view.View +import android.view.ViewGroup.MarginLayoutParams import android.view.WindowManager import androidx.activity.viewModels import androidx.core.graphics.Insets @@ -21,6 +22,7 @@ import androidx.core.view.OnApplyWindowInsetsListener import androidx.core.view.WindowInsetsCompat import androidx.core.view.isGone import androidx.core.view.isVisible +import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import androidx.lifecycle.lifecycleScope import com.google.android.material.snackbar.Snackbar @@ -333,11 +335,11 @@ class ReaderActivity : right = systemBars.right, left = systemBars.left, ) - viewBinding.appbarBottom?.updatePadding( - bottom = systemBars.bottom, - right = systemBars.right, - left = systemBars.left, - ) + viewBinding.appbarBottom?.updateLayoutParams { + bottomMargin = systemBars.bottom + topMargin + rightMargin = systemBars.right + topMargin + leftMargin = systemBars.left + topMargin + } return WindowInsetsCompat.Builder(insets) .setInsets(WindowInsetsCompat.Type.systemBars(), Insets.NONE) .build() @@ -373,19 +375,15 @@ class ReaderActivity : } private fun onUiStateChanged(pair: Pair) { - val (uiState: ReaderUiState?, previous: ReaderUiState?) = pair - title = uiState?.chapterName ?: uiState?.mangaName ?: getString(R.string.loading_) + val (previous: ReaderUiState?, uiState: ReaderUiState?) = pair + title = uiState?.resolveTitle(this) ?: getString(R.string.loading_) viewBinding.infoBar.update(uiState) if (uiState == null) { supportActionBar?.subtitle = null viewBinding.slider.isVisible = false return } - supportActionBar?.subtitle = if (uiState.chapterNumber in 1..uiState.chaptersTotal) { - getString(R.string.chapter_d_of_d, uiState.chapterNumber, uiState.chaptersTotal) - } else { - null - } + supportActionBar?.subtitle = uiState.chapterName if (previous?.chapterName != null && uiState.chapterName != previous.chapterName) { if (!uiState.chapterName.isNullOrEmpty()) { viewBinding.toastView.showTemporary(uiState.chapterName, TOAST_DURATION) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index f32dbbbb6..0ccbac877 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -366,6 +366,7 @@ class ReaderViewModel @Inject constructor( val chapter = state?.chapterId?.let { chaptersLoader.peekChapter(it) } val newState = ReaderUiState( mangaName = manga?.any?.title, + branch = chapter?.branch, chapterName = chapter?.name, chapterNumber = chapter?.number ?: 0, chaptersTotal = manga?.any?.getChapters(chapter?.branch)?.size ?: 0, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt index 4fa2db3f8..3994526dd 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigBottomSheet.kt @@ -41,7 +41,8 @@ class ReaderConfigBottomSheet : ActivityResultCallback, View.OnClickListener, MaterialButtonToggleGroup.OnButtonCheckedListener, - Slider.OnChangeListener, CompoundButton.OnCheckedChangeListener { + Slider.OnChangeListener, + CompoundButton.OnCheckedChangeListener { private val viewModel by activityViewModels() private val savePageRequest = registerForActivityResult(PageSaveContract(), this) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/ReaderUiState.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/ReaderUiState.kt index e97192ecf..650c4439a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/ReaderUiState.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/ReaderUiState.kt @@ -1,7 +1,11 @@ package org.koitharu.kotatsu.reader.ui.pager +import android.content.Context +import org.koitharu.kotatsu.R + data class ReaderUiState( val mangaName: String?, + val branch: String?, val chapterName: String?, val chapterNumber: Int, val chaptersTotal: Int, @@ -14,4 +18,10 @@ data class ReaderUiState( fun isSliderAvailable(): Boolean { return isSliderEnabled && totalPages > 1 && currentPage < totalPages } + + fun resolveTitle(context: Context): String? = when { + mangaName == null -> null + branch == null -> mangaName + else -> context.getString(R.string.manga_branch_title_template, mangaName, branch) + } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt index 39255497c..72293932c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt @@ -124,6 +124,7 @@ class PagesThumbnailsSheet : } else { headerBar.subtitle = null } + viewBinding?.recyclerView?.isFastScrollerEnabled = isExpanded } private inner class ScrollListener : BoundsScrollListener(3, 3) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAdapter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAdapter.kt index e1169638a..1b197fdb6 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAdapter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAdapter.kt @@ -1,10 +1,12 @@ package org.koitharu.kotatsu.reader.ui.thumbnails.adapter +import android.content.Context import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.DiffUtil import coil.ImageLoader import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD import org.koitharu.kotatsu.list.ui.model.ListHeader @@ -16,7 +18,7 @@ class PageThumbnailAdapter( coil: ImageLoader, lifecycleOwner: LifecycleOwner, clickListener: OnListItemClickListener, -) : AsyncListDifferDelegationAdapter(DiffCallback()) { +) : AsyncListDifferDelegationAdapter(DiffCallback()), FastScroller.SectionIndexer { init { delegatesManager.addDelegate(ITEM_TYPE_THUMBNAIL, pageThumbnailAD(coil, lifecycleOwner, clickListener)) @@ -24,6 +26,17 @@ class PageThumbnailAdapter( .addDelegate(ITEM_LOADING, loadingFooterAD()) } + override fun getSectionText(context: Context, position: Int): CharSequence? { + val list = items + for (i in (0..position).reversed()) { + val item = list.getOrNull(i) ?: continue + if (item is ListHeader) { + return item.getText(context) + } + } + return null + } + private class DiffCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: ListModel, newItem: ListModel): Boolean { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/adapter/FeedAdapter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/adapter/FeedAdapter.kt index 64963e946..063e17d8c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/adapter/FeedAdapter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/adapter/FeedAdapter.kt @@ -1,9 +1,11 @@ package org.koitharu.kotatsu.tracker.ui.feed.adapter +import android.content.Context import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.DiffUtil import coil.ImageLoader import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter +import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller import org.koitharu.kotatsu.core.ui.model.DateTimeAgo import org.koitharu.kotatsu.list.ui.adapter.MangaListListener import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD @@ -21,7 +23,7 @@ class FeedAdapter( coil: ImageLoader, lifecycleOwner: LifecycleOwner, listener: MangaListListener, -) : AsyncListDifferDelegationAdapter(DiffCallback()) { +) : AsyncListDifferDelegationAdapter(DiffCallback()), FastScroller.SectionIndexer { init { delegatesManager @@ -34,6 +36,17 @@ class FeedAdapter( .addDelegate(ITEM_TYPE_DATE_HEADER, relatedDateItemAD()) } + override fun getSectionText(context: Context, position: Int): CharSequence? { + val list = items + for (i in (0..position).reversed()) { + val item = list.getOrNull(i) ?: continue + if (item is DateTimeAgo) { + return item.format(context.resources) + } + } + return null + } + private class DiffCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: ListModel, newItem: ListModel) = when { diff --git a/app/src/main/res/layout-w600dp/activity_reader.xml b/app/src/main/res/layout-w600dp/activity_reader.xml index 051bfefe5..50b3da7ee 100644 --- a/app/src/main/res/layout-w600dp/activity_reader.xml +++ b/app/src/main/res/layout-w600dp/activity_reader.xml @@ -1,5 +1,5 @@ - - - + android:elevation="@dimen/m3_card_elevated_elevation" + app:elevation="@dimen/m3_card_elevated_elevation" + app:liftOnScroll="false"> + android:layout_weight="1" /> + app:menu="@menu/opt_reader_bottom"> + + - + diff --git a/app/src/main/res/layout-w600dp/fragment_details.xml b/app/src/main/res/layout-w600dp/fragment_details.xml index 81e1c7403..bad58eb53 100644 --- a/app/src/main/res/layout-w600dp/fragment_details.xml +++ b/app/src/main/res/layout-w600dp/fragment_details.xml @@ -206,6 +206,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:showAnimationBehavior="inward" + app:trackCornerRadius="0dp" tools:visibility="visible" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/activity_reader.xml b/app/src/main/res/layout/activity_reader.xml index 06ad562fe..8c97641da 100644 --- a/app/src/main/res/layout/activity_reader.xml +++ b/app/src/main/res/layout/activity_reader.xml @@ -1,5 +1,5 @@ - - - + android:elevation="@dimen/m3_card_elevated_elevation" + app:elevation="@dimen/m3_card_elevated_elevation" + app:liftOnScroll="false"> - + android:layout_margin="8dp" + app:layout_insetEdge="bottom"> + app:menu="@menu/opt_reader_bottom"> - + + + + android:indeterminate="true" + app:trackCornerRadius="@dimen/mtrl_progress_indicator_full_rounded_corner_radius" /> - + diff --git a/app/src/main/res/layout/fragment_details.xml b/app/src/main/res/layout/fragment_details.xml index 4af56cca4..ff371e036 100644 --- a/app/src/main/res/layout/fragment_details.xml +++ b/app/src/main/res/layout/fragment_details.xml @@ -218,6 +218,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:showAnimationBehavior="inward" + app:trackCornerRadius="0dp" tools:visibility="visible" /> - + android:layout_height="match_parent"> + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index aee909a83..2c3977217 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -424,4 +424,5 @@ Port Proxy Invalid value + %1$s (%2$s) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 098dd4768..452574345 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -76,6 +76,14 @@ 18sp + + + + + + From da4aedca979c54f0b42548b72f705984c4ab7fb1 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 3 Jun 2023 16:54:04 +0300 Subject: [PATCH 27/94] Fix proxy authentication --- .../core/network/ProxyAuthenticator.kt | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/ProxyAuthenticator.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/ProxyAuthenticator.kt index bc1fb8d53..fb4ffad7e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/ProxyAuthenticator.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/ProxyAuthenticator.kt @@ -6,12 +6,24 @@ import okhttp3.Request import okhttp3.Response import okhttp3.Route import org.koitharu.kotatsu.core.prefs.AppSettings +import java.net.PasswordAuthentication +import java.net.Proxy class ProxyAuthenticator( private val settings: AppSettings, -) : Authenticator { +) : Authenticator, java.net.Authenticator() { + + init { + setDefault(this) + } override fun authenticate(route: Route?, response: Response): Request? { + if (!isProxyEnabled()) { + return null + } + if (response.request.header(CommonHeaders.PROXY_AUTHORIZATION) != null) { + return null + } val login = settings.proxyLogin ?: return null val password = settings.proxyPassword ?: return null val credential = Credentials.basic(login, password) @@ -19,4 +31,15 @@ class ProxyAuthenticator( .header(CommonHeaders.PROXY_AUTHORIZATION, credential) .build() } + + override fun getPasswordAuthentication(): PasswordAuthentication? { + if (!isProxyEnabled()) { + return null + } + val login = settings.proxyLogin ?: return null + val password = settings.proxyPassword ?: return null + return PasswordAuthentication(login, password.toCharArray()) + } + + private fun isProxyEnabled() = settings.proxyType != Proxy.Type.DIRECT } From b48c6d7d3888175ad22fb0b575055a13c2aacc94 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 4 Jun 2023 15:42:15 +0300 Subject: [PATCH 28/94] Fix pages bottom sheet scroll --- .../core/ui/list/BoundsScrollListener.kt | 13 +++++- .../ScrollListenerInvalidationObserver.kt | 30 ------------- .../kotatsu/core/util/CompositeRunnable.kt | 12 ++++++ .../koitharu/kotatsu/core/util/ext/Other.kt | 14 ++++++ .../ui/thumbnails/PagesThumbnailsSheet.kt | 43 +++++++++++++++---- .../ui/thumbnails/PagesThumbnailsViewModel.kt | 14 +++++- app/src/main/res/layout/sheet_pages.xml | 2 +- 7 files changed, 84 insertions(+), 44 deletions(-) delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/ScrollListenerInvalidationObserver.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/util/CompositeRunnable.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/BoundsScrollListener.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/BoundsScrollListener.kt index f9d41fec8..9aa7cdf93 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/BoundsScrollListener.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/BoundsScrollListener.kt @@ -3,8 +3,10 @@ package org.koitharu.kotatsu.core.ui.list import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -abstract class BoundsScrollListener(private val offsetTop: Int, private val offsetBottom: Int) : - RecyclerView.OnScrollListener() { +abstract class BoundsScrollListener( + @JvmField protected val offsetTop: Int, + @JvmField protected val offsetBottom: Int +) : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) @@ -24,9 +26,16 @@ abstract class BoundsScrollListener(private val offsetTop: Int, private val offs if (firstVisibleItemPosition <= offsetTop) { onScrolledToStart(recyclerView) } + onPostScrolled(recyclerView, firstVisibleItemPosition, visibleItemCount) } abstract fun onScrolledToStart(recyclerView: RecyclerView) abstract fun onScrolledToEnd(recyclerView: RecyclerView) + + protected open fun onPostScrolled( + recyclerView: RecyclerView, + firstVisibleItemPosition: Int, + visibleItemCount: Int + ) = Unit } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/ScrollListenerInvalidationObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/ScrollListenerInvalidationObserver.kt deleted file mode 100644 index 5acc5862c..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/ScrollListenerInvalidationObserver.kt +++ /dev/null @@ -1,30 +0,0 @@ -package org.koitharu.kotatsu.core.ui.list - -import androidx.recyclerview.widget.RecyclerView - -class ScrollListenerInvalidationObserver( - private val recyclerView: RecyclerView, - private val scrollListener: RecyclerView.OnScrollListener, -) : RecyclerView.AdapterDataObserver() { - - override fun onChanged() { - super.onChanged() - invalidateScroll() - } - - override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { - super.onItemRangeInserted(positionStart, itemCount) - invalidateScroll() - } - - override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) { - super.onItemRangeRemoved(positionStart, itemCount) - invalidateScroll() - } - - private fun invalidateScroll() { - recyclerView.post { - scrollListener.onScrolled(recyclerView, 0, 0) - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/CompositeRunnable.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/CompositeRunnable.kt new file mode 100644 index 000000000..fe56ffc3c --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/CompositeRunnable.kt @@ -0,0 +1,12 @@ +package org.koitharu.kotatsu.core.util + +class CompositeRunnable( + private val children: List, +) : Runnable, Collection by children { + + override fun run() { + for (child in children) { + child.run() + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Other.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Other.kt index baf078b7f..046bd94ca 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Other.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Other.kt @@ -1,5 +1,7 @@ package org.koitharu.kotatsu.core.util.ext +import org.koitharu.kotatsu.core.util.CompositeRunnable + @Suppress("UNCHECKED_CAST") fun Class.castOrNull(obj: Any?): T? { if (obj == null || !isInstance(obj)) { @@ -7,3 +9,15 @@ fun Class.castOrNull(obj: Any?): T? { } return obj as T } + +/* CompositeRunnable */ + +operator fun Runnable.plus(other: Runnable): Runnable { + val list = ArrayList(this.size + other.size) + if (this is CompositeRunnable) list.addAll(this) else list.add(this) + if (other is CompositeRunnable) list.addAll(other) else list.add(other) + return CompositeRunnable(list) +} + +private val Runnable.size: Int + get() = if (this is CompositeRunnable) size else 1 diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt index 4f49f9bad..a5aa7ac9c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt @@ -16,23 +16,25 @@ import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.list.BoundsScrollListener import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener -import org.koitharu.kotatsu.core.ui.list.ScrollListenerInvalidationObserver import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetBehavior import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetCallback import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet +import org.koitharu.kotatsu.core.util.RecyclerViewScrollCallback import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observeEvent +import org.koitharu.kotatsu.core.util.ext.plus import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.SheetPagesBinding import org.koitharu.kotatsu.list.ui.MangaListSpanResolver +import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.reader.ui.ReaderActivity import org.koitharu.kotatsu.reader.ui.ReaderState import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.PageThumbnailAdapter -import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.TargetScrollObserver import javax.inject.Inject +import kotlin.math.roundToInt @AndroidEntryPoint class PagesThumbnailsSheet : @@ -79,14 +81,8 @@ class PagesThumbnailsSheet : spanResolver?.setGridSize(settings.gridSize / 100f, this) addOnScrollListener(ScrollListener().also { scrollListener = it }) (layoutManager as GridLayoutManager).spanSizeLookup = spanSizeLookup - thumbnailsAdapter?.registerAdapterDataObserver( - ScrollListenerInvalidationObserver(this, checkNotNull(scrollListener)), - ) - thumbnailsAdapter?.registerAdapterDataObserver(TargetScrollObserver(this)) - } - viewModel.thumbnails.observe(viewLifecycleOwner) { - thumbnailsAdapter?.setItems(it, listCommitCallback) } + viewModel.thumbnails.observe(viewLifecycleOwner, ::onThumbnailsChanged) viewModel.branch.observe(viewLifecycleOwner, ::updateTitle) viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) } @@ -124,6 +120,28 @@ class PagesThumbnailsSheet : } } + private fun onThumbnailsChanged(list: List) { + val adapter = thumbnailsAdapter ?: return + if (adapter.itemCount == 0) { + var position = list.indexOfFirst { it is PageThumbnail && it.isCurrent } + if (position > 0) { + val spanCount = spanResolver?.spanCount ?: 0 + val offset = if (position > spanCount + 1) { + (resources.getDimensionPixelSize(R.dimen.manga_list_details_item_height) * 0.6).roundToInt() + } else { + position = 0 + 0 + } + val scrollCallback = RecyclerViewScrollCallback(requireViewBinding().recyclerView, position, offset) + adapter.setItems(list, listCommitCallback + scrollCallback) + } else { + adapter.setItems(list, listCommitCallback) + } + } else { + adapter.setItems(list, listCommitCallback) + } + } + private inner class ScrollListener : BoundsScrollListener(3, 3) { override fun onScrolledToStart(recyclerView: RecyclerView) { @@ -133,6 +151,13 @@ class PagesThumbnailsSheet : override fun onScrolledToEnd(recyclerView: RecyclerView) { viewModel.loadNextChapter() } + + override fun onPostScrolled(recyclerView: RecyclerView, firstVisibleItemPosition: Int, visibleItemCount: Int) { + super.onPostScrolled(recyclerView, firstVisibleItemPosition, visibleItemCount) + if (firstVisibleItemPosition > offsetTop) { + viewModel.allowLoadAbove() + } + } } private inner class SpanSizeLookup : GridLayoutManager.SpanSizeLookup() { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt index 8116560fa..ef0463ba0 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsViewModel.kt @@ -39,6 +39,7 @@ class PagesThumbnailsViewModel @Inject constructor( private var loadingJob: Job? = null private var loadingPrevJob: Job? = null private var loadingNextJob: Job? = null + private var isLoadAboveAllowed = false val thumbnails = MutableStateFlow>(emptyList()) val branch = MutableStateFlow(null) @@ -51,8 +52,17 @@ class PagesThumbnailsViewModel @Inject constructor( } } + fun allowLoadAbove() { + if (!isLoadAboveAllowed) { + loadingJob = launchJob(Dispatchers.Default) { + isLoadAboveAllowed = true + updateList() + } + } + } + fun loadPrevChapter() { - if (loadingJob?.isActive == true || loadingPrevJob?.isActive == true) { + if (!isLoadAboveAllowed || loadingJob?.isActive == true || loadingPrevJob?.isActive == true) { return } loadingPrevJob = loadPrevNextChapter(isNext = false) @@ -74,7 +84,7 @@ class PagesThumbnailsViewModel @Inject constructor( private suspend fun updateList() { val snapshot = chaptersLoader.snapshot() val mangaChapters = mangaDetails.tryGet().getOrNull()?.chapters.orEmpty() - val hasPrevChapter = snapshot.firstOrNull()?.chapterId != mangaChapters.firstOrNull()?.id + val hasPrevChapter = isLoadAboveAllowed && snapshot.firstOrNull()?.chapterId != mangaChapters.firstOrNull()?.id val hasNextChapter = snapshot.lastOrNull()?.chapterId != mangaChapters.lastOrNull()?.id val pages = buildList(snapshot.size + chaptersLoader.size + 2) { if (hasPrevChapter) { diff --git a/app/src/main/res/layout/sheet_pages.xml b/app/src/main/res/layout/sheet_pages.xml index 986ea651b..140e944af 100644 --- a/app/src/main/res/layout/sheet_pages.xml +++ b/app/src/main/res/layout/sheet_pages.xml @@ -19,7 +19,7 @@ Date: Sun, 4 Jun 2023 16:02:38 +0300 Subject: [PATCH 29/94] Set style for drag handle globally --- app/src/main/res/layout/activity_details.xml | 1 - app/src/main/res/layout/layout_sheet_header_adaptive.xml | 1 - app/src/main/res/values/themes.xml | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/res/layout/activity_details.xml b/app/src/main/res/layout/activity_details.xml index c73fd7075..7e6f0e8d1 100644 --- a/app/src/main/res/layout/activity_details.xml +++ b/app/src/main/res/layout/activity_details.xml @@ -55,7 +55,6 @@ android:orientation="vertical"> diff --git a/app/src/main/res/layout/layout_sheet_header_adaptive.xml b/app/src/main/res/layout/layout_sheet_header_adaptive.xml index 616360f18..0f5bead1c 100644 --- a/app/src/main/res/layout/layout_sheet_header_adaptive.xml +++ b/app/src/main/res/layout/layout_sheet_header_adaptive.xml @@ -9,7 +9,6 @@ tools:parentTag="android.widget.LinearLayout"> @style/Widget.Material3.CollapsingToolbar.Medium @style/Widget.Kotatsu.CircularProgressIndicator @style/Widget.Kotatsu.LinearProgressIndicator + @style/Widget.Kotatsu.BottomSheet.DragHandle @style/TextAppearance.Kotatsu.Menu From 46b797fc67bf16af0928a7e2f6f01b8ef62537a0 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 4 Jun 2023 15:56:57 +0300 Subject: [PATCH 30/94] Fix chapters bottom sheet header size --- .../koitharu/kotatsu/details/ui/DetailsActivity.kt | 3 +++ app/src/main/res/layout/activity_details.xml | 13 +++++++++---- .../res/layout/layout_sheet_header_adaptive.xml | 2 ++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index 0acb146c1..038348767 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -243,6 +243,9 @@ class DetailsActivity : viewBinding.cardChapters?.updateLayoutParams { bottomMargin = insets.bottom + marginEnd } + viewBinding.dragHandle?.updateLayoutParams { + bottomMargin = insets.bottom + } } private fun onHistoryChanged(info: HistoryInfo) { diff --git a/app/src/main/res/layout/activity_details.xml b/app/src/main/res/layout/activity_details.xml index 7e6f0e8d1..579adf35d 100644 --- a/app/src/main/res/layout/activity_details.xml +++ b/app/src/main/res/layout/activity_details.xml @@ -48,7 +48,7 @@ app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.BottomSheet" tools:visibility="visible"> - + android:layout_height="?actionBarSize" + android:layout_gravity="top" + android:paddingTop="0dp" + android:paddingBottom="32dp" + tools:layout_marginBottom="14dp" /> @@ -92,7 +97,7 @@ - + From b5705b45dfa26ad6c2bcaeb09ed174ebd3628253 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 4 Jun 2023 15:59:44 +0300 Subject: [PATCH 31/94] Add port number validation --- .../kotatsu/settings/ProxySettingsFragment.kt | 4 +++- .../kotatsu/settings/SourceSettingsExt.kt | 2 ++ .../{ => utils/validation}/DomainValidator.kt | 2 +- .../{ => utils/validation}/HeaderValidator.kt | 2 +- .../utils/validation/PortNumberValidator.kt | 24 +++++++++++++++++++ .../kotatsu/sync/ui/SyncHostDialogFragment.kt | 2 +- app/src/main/res/values/strings.xml | 1 + 7 files changed, 33 insertions(+), 4 deletions(-) rename app/src/main/kotlin/org/koitharu/kotatsu/settings/{ => utils/validation}/DomainValidator.kt (93%) rename app/src/main/kotlin/org/koitharu/kotatsu/settings/{ => utils/validation}/HeaderValidator.kt (92%) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/utils/validation/PortNumberValidator.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/ProxySettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/ProxySettingsFragment.kt index ab6097f5f..4125d46e2 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/ProxySettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/ProxySettingsFragment.kt @@ -13,6 +13,8 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BasePreferenceFragment import org.koitharu.kotatsu.settings.utils.EditTextBindListener import org.koitharu.kotatsu.settings.utils.PasswordSummaryProvider +import org.koitharu.kotatsu.settings.utils.validation.DomainValidator +import org.koitharu.kotatsu.settings.utils.validation.PortNumberValidator import java.net.Proxy @AndroidEntryPoint @@ -32,7 +34,7 @@ class ProxySettingsFragment : BasePreferenceFragment(R.string.proxy), EditTextBindListener( inputType = EditorInfo.TYPE_CLASS_NUMBER, hint = null, - validator = null, + validator = PortNumberValidator(), ), ) findPreference(AppSettings.KEY_PROXY_PASSWORD)?.let { pref -> diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SourceSettingsExt.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SourceSettingsExt.kt index 6a83af617..d0123bee7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SourceSettingsExt.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SourceSettingsExt.kt @@ -11,6 +11,8 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.settings.utils.AutoCompleteTextViewPreference import org.koitharu.kotatsu.settings.utils.EditTextBindListener import org.koitharu.kotatsu.settings.utils.EditTextDefaultSummaryProvider +import org.koitharu.kotatsu.settings.utils.validation.DomainValidator +import org.koitharu.kotatsu.settings.utils.validation.HeaderValidator fun PreferenceFragmentCompat.addPreferencesFromRepository(repository: RemoteMangaRepository) { val configKeys = repository.getConfigKeys() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/DomainValidator.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/utils/validation/DomainValidator.kt similarity index 93% rename from app/src/main/kotlin/org/koitharu/kotatsu/settings/DomainValidator.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/settings/utils/validation/DomainValidator.kt index 0ac467edc..201fabeec 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/DomainValidator.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/utils/validation/DomainValidator.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.settings +package org.koitharu.kotatsu.settings.utils.validation import okhttp3.HttpUrl import org.koitharu.kotatsu.R diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/HeaderValidator.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/utils/validation/HeaderValidator.kt similarity index 92% rename from app/src/main/kotlin/org/koitharu/kotatsu/settings/HeaderValidator.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/settings/utils/validation/HeaderValidator.kt index b25be70d6..36891f980 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/HeaderValidator.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/utils/validation/HeaderValidator.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.settings +package org.koitharu.kotatsu.settings.utils.validation import okhttp3.Headers import org.koitharu.kotatsu.R diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/utils/validation/PortNumberValidator.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/utils/validation/PortNumberValidator.kt new file mode 100644 index 000000000..3bee9f9a5 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/utils/validation/PortNumberValidator.kt @@ -0,0 +1,24 @@ +package org.koitharu.kotatsu.settings.utils.validation + +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.util.EditTextValidator + +class PortNumberValidator : EditTextValidator() { + + override fun validate(text: String): ValidationResult { + val trimmed = text.trim() + if (trimmed.isEmpty()) { + return ValidationResult.Success + } + return if (!checkCharacters(trimmed)) { + ValidationResult.Failed(context.getString(R.string.invalid_port_number)) + } else { + ValidationResult.Success + } + } + + private fun checkCharacters(value: String): Boolean { + val intValue = value.toIntOrNull() ?: return false + return intValue in 1..65535 + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncHostDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncHostDialogFragment.kt index 735adb19a..2de3183f4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncHostDialogFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/sync/ui/SyncHostDialogFragment.kt @@ -14,7 +14,7 @@ import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.AlertDialogFragment import org.koitharu.kotatsu.databinding.PreferenceDialogAutocompletetextviewBinding -import org.koitharu.kotatsu.settings.DomainValidator +import org.koitharu.kotatsu.settings.utils.validation.DomainValidator import org.koitharu.kotatsu.sync.data.SyncSettings import javax.inject.Inject diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eb9f3d1f4..5dad409f3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -432,4 +432,5 @@ Username Password Authorization (optional) + Invalid port number From 12d8d3e2d117354e810a0ac3872afb541954e74a Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 4 Jun 2023 16:04:36 +0300 Subject: [PATCH 32/94] Set AppProxySelector as default --- .../org/koitharu/kotatsu/core/network/AppProxySelector.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/AppProxySelector.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/AppProxySelector.kt index 5beb6e42a..7d67a40fd 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/AppProxySelector.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/AppProxySelector.kt @@ -13,6 +13,10 @@ class AppProxySelector( private val settings: AppSettings, ) : ProxySelector() { + init { + setDefault(this) + } + private var cachedProxy: Proxy? = null override fun select(uri: URI?): List { From 02d5dfb37599ebd15fa34f5ad71056c70b319f40 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 4 Jun 2023 16:50:09 +0300 Subject: [PATCH 33/94] Check if page file valid before page display --- .../koitharu/kotatsu/core/util/ext/File.kt | 2 ++ .../kotatsu/core/util/ext/Throwable.kt | 3 +++ .../koitharu/kotatsu/local/data/PagesCache.kt | 20 ++++++++++++++++++- .../kotatsu/reader/domain/PageLoader.kt | 13 +++++++++++- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/File.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/File.kt index ac98e2b48..79877887b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/File.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/File.kt @@ -26,6 +26,8 @@ fun File.takeIfReadable() = takeIf { it.exists() && it.canRead() } fun File.takeIfWriteable() = takeIf { it.exists() && it.canWrite() } +fun File.isNotEmpty() = length() != 0L + fun ZipFile.readText(entry: ZipEntry) = getInputStream(entry).bufferedReader().use { it.readText() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt index 3623d56d1..29defe131 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt @@ -87,3 +87,6 @@ fun Throwable.isWebViewUnavailable(): Boolean { return (this is AndroidRuntimeException && message?.contains("WebView") == true) || cause?.isWebViewUnavailable() == true } + +@Suppress("FunctionName") +fun NoSpaceLeftException() = IOException(MSG_NO_SPACE_LEFT) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/PagesCache.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/PagesCache.kt index 336fe6511..a39f01262 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/PagesCache.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/PagesCache.kt @@ -1,6 +1,7 @@ package org.koitharu.kotatsu.local.data import android.content.Context +import android.os.StatFs import com.tomclaw.cache.DiskLruCache import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers @@ -33,7 +34,8 @@ class PagesCache @Inject constructor(@ApplicationContext context: Context) { } private val lruCache = SuspendLazy { val dir = cacheDir.get() - val size = FileSize.MEGABYTES.convert(200, FileSize.BYTES) + val availableSize = getAvailableSizeMb() + val size = SIZE_DEFAULT.coerceIn(SIZE_MIN, availableSize) runCatchingCancellable { DiskLruCache.create(dir, size) }.recoverCatching { error -> @@ -63,4 +65,20 @@ class PagesCache @Inject constructor(@ApplicationContext context: Context) { file.delete() } } + + private suspend fun getAvailableSizeMb(): Long = runCatchingCancellable { + val statFs = StatFs(cacheDir.get().absolutePath) + FileSize.BYTES.convert(statFs.availableBytes, FileSize.MEGABYTES) + }.onFailure { + it.printStackTraceDebug() + }.getOrDefault(SIZE_DEFAULT) + + private companion object { + + val SIZE_MIN + get() = FileSize.MEGABYTES.convert(20, FileSize.BYTES) + + val SIZE_DEFAULT + get() = FileSize.MEGABYTES.convert(200, FileSize.BYTES) + } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt index d37d80a30..eeac2ce29 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt @@ -12,6 +12,7 @@ import dagger.hilt.android.lifecycle.RetainedLifecycle import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.scopes.ActivityRetainedScoped import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.flow.MutableStateFlow @@ -32,6 +33,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.FileSize import org.koitharu.kotatsu.core.util.RetainedLifecycleCoroutineScope import org.koitharu.kotatsu.core.util.ext.ensureSuccess +import org.koitharu.kotatsu.core.util.ext.isNotEmpty import org.koitharu.kotatsu.core.util.ext.ramAvailable import org.koitharu.kotatsu.core.util.ext.withProgress import org.koitharu.kotatsu.core.util.progress.ProgressDeferred @@ -103,7 +105,7 @@ class PageLoader @Inject constructor( } fun loadPageAsync(page: MangaPage, force: Boolean): ProgressDeferred { - var task = tasks[page.id] + var task = tasks[page.id]?.takeIf { it.isValid() } if (force) { task?.cancel() } else if (task?.isCancelled == false) { @@ -216,6 +218,15 @@ class PageLoader @Inject constructor( return context.ramAvailable <= FileSize.MEGABYTES.convert(PREFETCH_MIN_RAM_MB, FileSize.BYTES) } + private fun Deferred.isValid(): Boolean { + return if (isCompleted) { + val file = getCompleted() + file.exists() && file.isNotEmpty() + } else { + true + } + } + private class InternalErrorHandler : AbstractCoroutineContextElement(CoroutineExceptionHandler), CoroutineExceptionHandler { From 1847759ec3ebb8fbf94d6eb7fe91414348ff1690 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 4 Jun 2023 17:37:54 +0300 Subject: [PATCH 34/94] Refactor list extra provider --- .../org/koitharu/kotatsu/core/AppModule.kt | 5 -- .../core/parser/MangaTagHighlighter.kt | 37 ----------- .../kotatsu/details/ui/DetailsFragment.kt | 6 +- .../ui/list/FavouritesListViewModel.kt | 30 ++------- .../kotatsu/history/data/HistoryDao.kt | 10 ++- .../kotatsu/history/data/HistoryRepository.kt | 6 ++ .../history/ui/HistoryListViewModel.kt | 20 ++---- .../kotatsu/list/domain/ListExtraProvider.kt | 60 ++++++++++++++++-- .../list/domain/ListExtraProviderImpl.kt | 32 ---------- .../list/ui/model/ListModelConversionExt.kt | 63 ++++++------------- .../kotatsu/local/ui/LocalListViewModel.kt | 3 - .../remotelist/ui/RemoteListViewModel.kt | 4 +- .../kotatsu/search/ui/SearchViewModel.kt | 6 +- .../search/ui/multi/MultiSearchViewModel.kt | 4 +- .../domain/ShelfContentObserveUseCase.kt | 11 ++-- .../shelf/domain/model/ShelfContent.kt | 5 +- .../kotatsu/shelf/ui/ShelfViewModel.kt | 49 ++++----------- .../suggestions/ui/SuggestionsViewModel.kt | 6 +- .../kotatsu/tracker/data/TracksDao.kt | 5 +- .../tracker/domain/TrackingRepository.kt | 5 +- .../tracker/ui/updates/UpdatesViewModel.kt | 33 ++-------- 21 files changed, 143 insertions(+), 257 deletions(-) delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaTagHighlighter.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProviderImpl.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt index 1aad04a76..25332e92e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt @@ -40,8 +40,6 @@ import org.koitharu.kotatsu.core.util.IncognitoModeIndicator import org.koitharu.kotatsu.core.util.ext.activityManager import org.koitharu.kotatsu.core.util.ext.connectivityManager import org.koitharu.kotatsu.core.util.ext.isLowRamDevice -import org.koitharu.kotatsu.list.domain.ListExtraProvider -import org.koitharu.kotatsu.list.domain.ListExtraProviderImpl import org.koitharu.kotatsu.local.data.CacheDir import org.koitharu.kotatsu.local.data.CbzFetcher import org.koitharu.kotatsu.local.data.LocalStorageChanges @@ -65,9 +63,6 @@ interface AppModule { @Binds fun bindImageGetter(coilImageGetter: CoilImageGetter): Html.ImageGetter - @Binds - fun bindListExtraProvider(impl: ListExtraProviderImpl): ListExtraProvider - companion object { @Provides diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaTagHighlighter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaTagHighlighter.kt deleted file mode 100644 index 7168445bd..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaTagHighlighter.kt +++ /dev/null @@ -1,37 +0,0 @@ -package org.koitharu.kotatsu.core.parser - -import android.content.Context -import androidx.annotation.ColorRes -import dagger.Reusable -import dagger.hilt.android.qualifiers.ApplicationContext -import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.parsers.model.MangaTag -import javax.inject.Inject - -@Reusable -class MangaTagHighlighter @Inject constructor( - @ApplicationContext context: Context, -) { - - private val dict by lazy { - context.resources.openRawResource(R.raw.tags_redlist).use { - val set = HashSet() - it.bufferedReader().forEachLine { x -> - val line = x.trim() - if (line.isNotEmpty()) { - set.add(line) - } - } - set - } - } - - @ColorRes - fun getTint(tag: MangaTag): Int { - return if (tag.title.lowercase() in dict) { - R.color.warning - } else { - 0 - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt index 7c581df2b..5cf4dc756 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt @@ -23,7 +23,6 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter import org.koitharu.kotatsu.core.model.countChaptersByBranch -import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.ui.BaseFragment import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener @@ -45,6 +44,7 @@ import org.koitharu.kotatsu.details.ui.scrobbling.ScrobblingItemDecoration import org.koitharu.kotatsu.details.ui.scrobbling.ScrollingInfoAdapter import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.image.ui.ImageActivity +import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.main.ui.owners.NoModalBottomSheetOwner import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource @@ -67,7 +67,7 @@ class DetailsFragment : lateinit var coil: ImageLoader @Inject - lateinit var tagHighlighter: MangaTagHighlighter + lateinit var tagHighlighter: ListExtraProvider private val viewModel by activityViewModels() @@ -283,7 +283,7 @@ class DetailsFragment : manga.tags.map { tag -> ChipsView.ChipModel( title = tag.title, - tint = tagHighlighter.getTint(tag), + tint = tagHighlighter.getTagTint(tag), icon = 0, data = tag, isCheckable = false, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt index 3c7ceb019..dea73f94f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt @@ -13,7 +13,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.util.ReversibleAction import org.koitharu.kotatsu.core.util.ext.call @@ -21,8 +20,6 @@ import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.ARG_CATEGORY_ID import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.NO_ID -import org.koitharu.kotatsu.history.data.HistoryRepository -import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState @@ -30,19 +27,16 @@ import org.koitharu.kotatsu.list.ui.model.LoadingState import org.koitharu.kotatsu.list.ui.model.toErrorState import org.koitharu.kotatsu.list.ui.model.toUi import org.koitharu.kotatsu.parsers.model.SortOrder -import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject @HiltViewModel class FavouritesListViewModel @Inject constructor( savedStateHandle: SavedStateHandle, private val repository: FavouritesRepository, - private val trackingRepository: TrackingRepository, - private val historyRepository: HistoryRepository, - private val settings: AppSettings, - private val tagHighlighter: MangaTagHighlighter, + private val listExtraProvider: ListExtraProvider, + settings: AppSettings, downloadScheduler: DownloadWorker.Scheduler, -) : MangaListViewModel(settings, downloadScheduler), ListExtraProvider { +) : MangaListViewModel(settings, downloadScheduler) { val categoryId: Long = savedStateHandle[ARG_CATEGORY_ID] ?: NO_ID @@ -76,7 +70,7 @@ class FavouritesListViewModel @Inject constructor( ), ) - else -> list.toUi(mode, this, tagHighlighter) + else -> list.toUi(mode, listExtraProvider) } }.catch { emit(listOf(it.toErrorState(canRetry = false))) @@ -108,20 +102,4 @@ class FavouritesListViewModel @Inject constructor( repository.setCategoryOrder(categoryId, order) } } - - override suspend fun getCounter(mangaId: Long): Int { - return if (settings.isTrackerEnabled) { - trackingRepository.getNewChaptersCount(mangaId) - } else { - 0 - } - } - - override suspend fun getProgress(mangaId: Long): Float { - return if (settings.isReadingIndicatorsEnabled) { - historyRepository.getProgress(mangaId) - } else { - PROGRESS_NONE - } - } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt index be2c5f7e9..0e033ddd5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt @@ -1,6 +1,10 @@ package org.koitharu.kotatsu.history.data -import androidx.room.* +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Transaction import kotlinx.coroutines.flow.Flow import org.koitharu.kotatsu.core.db.entity.MangaEntity import org.koitharu.kotatsu.core.db.entity.TagEntity @@ -20,6 +24,10 @@ abstract class HistoryDao { @Query("SELECT * FROM history WHERE deleted_at = 0 ORDER BY updated_at DESC") abstract fun observeAll(): Flow> + @Transaction + @Query("SELECT * FROM history WHERE deleted_at = 0 ORDER BY updated_at DESC LIMIT :limit") + abstract fun observeAll(limit: Int): Flow> + @Query("SELECT * FROM manga WHERE manga_id IN (SELECT manga_id FROM history WHERE deleted_at = 0)") abstract suspend fun findAllManga(): List diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt index f8977fabf..3cd576e87 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt @@ -51,6 +51,12 @@ class HistoryRepository @Inject constructor( } } + fun observeAll(limit: Int): Flow> { + return db.historyDao.observeAll(limit).mapItems { + it.manga.toManga(it.tags.toMangaTags()) + } + } + fun observeAllWithHistory(): Flow> { return db.historyDao.observeAll().mapItems { MangaWithHistory( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt index c46f349db..673fbc87d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt @@ -10,7 +10,6 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.prefs.observeAsStateFlow @@ -21,8 +20,8 @@ import org.koitharu.kotatsu.core.util.ext.daysDiff import org.koitharu.kotatsu.core.util.ext.onFirst import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.history.data.HistoryRepository -import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.history.domain.model.MangaWithHistory +import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel @@ -31,7 +30,6 @@ import org.koitharu.kotatsu.list.ui.model.toErrorState import org.koitharu.kotatsu.list.ui.model.toGridModel import org.koitharu.kotatsu.list.ui.model.toListDetailedModel import org.koitharu.kotatsu.list.ui.model.toListModel -import org.koitharu.kotatsu.tracker.domain.TrackingRepository import java.util.Date import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -40,8 +38,7 @@ import javax.inject.Inject class HistoryListViewModel @Inject constructor( private val repository: HistoryRepository, private val settings: AppSettings, - private val trackingRepository: TrackingRepository, - private val tagHighlighter: MangaTagHighlighter, + private val extraProvider: ListExtraProvider, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { @@ -106,7 +103,6 @@ class HistoryListViewModel @Inject constructor( mode: ListMode, ): List { val result = ArrayList(if (grouped) (list.size * 1.4).toInt() else list.size + 1) - val showPercent = settings.isReadingIndicatorsEnabled var prevDate: DateTimeAgo? = null for ((manga, history) in list) { if (grouped) { @@ -116,16 +112,10 @@ class HistoryListViewModel @Inject constructor( } prevDate = date } - val counter = if (settings.isTrackerEnabled) { - trackingRepository.getNewChaptersCount(manga.id) - } else { - 0 - } - val percent = if (showPercent) history.percent else PROGRESS_NONE result += when (mode) { - ListMode.LIST -> manga.toListModel(counter, percent) - ListMode.DETAILED_LIST -> manga.toListDetailedModel(counter, percent, tagHighlighter) - ListMode.GRID -> manga.toGridModel(counter, percent) + ListMode.LIST -> manga.toListModel(extraProvider) + ListMode.DETAILED_LIST -> manga.toListDetailedModel(extraProvider) + ListMode.GRID -> manga.toGridModel(extraProvider) } } return result diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt index 7c547e0ae..60cc18885 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt @@ -1,8 +1,60 @@ package org.koitharu.kotatsu.list.domain -interface ListExtraProvider { +import android.content.Context +import androidx.annotation.ColorRes +import dagger.Reusable +import dagger.hilt.android.qualifiers.ApplicationContext +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.history.data.PROGRESS_NONE +import org.koitharu.kotatsu.parsers.model.MangaTag +import org.koitharu.kotatsu.tracker.domain.TrackingRepository +import javax.inject.Inject - suspend fun getCounter(mangaId: Long): Int +@Reusable +class ListExtraProvider @Inject constructor( + @ApplicationContext context: Context, + private val settings: AppSettings, + private val trackingRepository: TrackingRepository, + private val historyRepository: HistoryRepository, +) { - suspend fun getProgress(mangaId: Long): Float -} \ No newline at end of file + private val dict by lazy { + context.resources.openRawResource(R.raw.tags_redlist).use { + val set = HashSet() + it.bufferedReader().forEachLine { x -> + val line = x.trim() + if (line.isNotEmpty()) { + set.add(line) + } + } + set + } + } + + suspend fun getCounter(mangaId: Long): Int { + return if (settings.isTrackerEnabled) { + trackingRepository.getNewChaptersCount(mangaId) + } else { + 0 + } + } + + suspend fun getProgress(mangaId: Long): Float { + return if (settings.isReadingIndicatorsEnabled) { + historyRepository.getProgress(mangaId) + } else { + PROGRESS_NONE + } + } + + @ColorRes + fun getTagTint(tag: MangaTag): Int { + return if (tag.title.lowercase() in dict) { + R.color.warning + } else { + 0 + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProviderImpl.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProviderImpl.kt deleted file mode 100644 index c972feb7e..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProviderImpl.kt +++ /dev/null @@ -1,32 +0,0 @@ -package org.koitharu.kotatsu.list.domain - -import dagger.Reusable -import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.history.data.HistoryRepository -import org.koitharu.kotatsu.history.data.PROGRESS_NONE -import org.koitharu.kotatsu.tracker.domain.TrackingRepository -import javax.inject.Inject - -@Reusable -class ListExtraProviderImpl @Inject constructor( - private val settings: AppSettings, - private val trackingRepository: TrackingRepository, - private val historyRepository: HistoryRepository, -) : ListExtraProvider { - - override suspend fun getCounter(mangaId: Long): Int { - return if (settings.isTrackerEnabled) { - trackingRepository.getNewChaptersCount(mangaId) - } else { - 0 - } - } - - override suspend fun getProgress(mangaId: Long): Float { - return if (settings.isReadingIndicatorsEnabled) { - historyRepository.getProgress(mangaId) - } else { - PROGRESS_NONE - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt index 172fe3aeb..aa6014626 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt @@ -3,7 +3,6 @@ package org.koitharu.kotatsu.list.ui.model import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver -import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.ui.widgets.ChipsView import org.koitharu.kotatsu.core.util.ext.ifZero @@ -14,34 +13,31 @@ import org.koitharu.kotatsu.parsers.model.Manga import java.net.SocketTimeoutException import java.net.UnknownHostException -fun Manga.toListModel( - counter: Int, - progress: Float, +suspend fun Manga.toListModel( + extraProvider: ListExtraProvider? ) = MangaListModel( id = id, title = title, subtitle = tags.joinToString(", ") { it.title }, coverUrl = coverUrl, manga = this, - counter = counter, - progress = progress, + counter = extraProvider?.getCounter(id) ?: 0, + progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE, ) -fun Manga.toListDetailedModel( - counter: Int, - progress: Float, - tagHighlighter: MangaTagHighlighter?, +suspend fun Manga.toListDetailedModel( + extraProvider: ListExtraProvider?, ) = MangaListDetailedModel( id = id, title = title, subtitle = altTitle, coverUrl = coverUrl, manga = this, - counter = counter, - progress = progress, + counter = extraProvider?.getCounter(id) ?: 0, + progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE, tags = tags.map { ChipsView.ChipModel( - tint = tagHighlighter?.getTint(it) ?: 0, + tint = extraProvider?.getTagTint(it) ?: 0, title = it.title, icon = 0, isCheckable = false, @@ -51,53 +47,30 @@ fun Manga.toListDetailedModel( }, ) -fun Manga.toGridModel(counter: Int, progress: Float) = MangaGridModel( +suspend fun Manga.toGridModel( + extraProvider: ListExtraProvider?, +) = MangaGridModel( id = id, title = title, coverUrl = coverUrl, manga = this, - counter = counter, - progress = progress, + counter = extraProvider?.getCounter(id) ?: 0, + progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE, ) suspend fun List.toUi( mode: ListMode, extraProvider: ListExtraProvider, - tagHighlighter: MangaTagHighlighter?, -): List = toUi(ArrayList(size), mode, extraProvider, tagHighlighter) - -fun List.toUi( - mode: ListMode, - tagHighlighter: MangaTagHighlighter?, -): List = toUi(ArrayList(size), mode, tagHighlighter) - -fun > List.toUi( - destination: C, - mode: ListMode, - tagHighlighter: MangaTagHighlighter?, -): C = when (mode) { - ListMode.LIST -> mapTo(destination) { it.toListModel(0, PROGRESS_NONE) } - ListMode.DETAILED_LIST -> mapTo(destination) { it.toListDetailedModel(0, PROGRESS_NONE, tagHighlighter) } - ListMode.GRID -> mapTo(destination) { it.toGridModel(0, PROGRESS_NONE) } -} +): List = toUi(ArrayList(size), mode, extraProvider) suspend fun > List.toUi( destination: C, mode: ListMode, extraProvider: ListExtraProvider, - tagHighlighter: MangaTagHighlighter?, ): C = when (mode) { - ListMode.LIST -> mapTo(destination) { - it.toListModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id)) - } - - ListMode.DETAILED_LIST -> mapTo(destination) { - it.toListDetailedModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id), tagHighlighter) - } - - ListMode.GRID -> mapTo(destination) { - it.toGridModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id)) - } + ListMode.LIST -> mapTo(destination) { it.toListModel(extraProvider) } + ListMode.DETAILED_LIST -> mapTo(destination) { it.toListDetailedModel(extraProvider) } + ListMode.GRID -> mapTo(destination) { it.toGridModel(extraProvider) } } fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt index 65f7a393e..99723036a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt @@ -6,7 +6,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharedFlow import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaRepository -import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call @@ -25,7 +24,6 @@ class LocalListViewModel @Inject constructor( savedStateHandle: SavedStateHandle, mangaRepositoryFactory: MangaRepository.Factory, filter: FilterCoordinator, - tagHighlighter: MangaTagHighlighter, settings: AppSettings, downloadScheduler: DownloadWorker.Scheduler, listExtraProvider: ListExtraProvider, @@ -35,7 +33,6 @@ class LocalListViewModel @Inject constructor( savedStateHandle, mangaRepositoryFactory, filter, - tagHighlighter, settings, listExtraProvider, downloadScheduler, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt index 130a34233..816c464f7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt @@ -18,7 +18,6 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaRepository -import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.require @@ -47,7 +46,6 @@ open class RemoteListViewModel @Inject constructor( savedStateHandle: SavedStateHandle, mangaRepositoryFactory: MangaRepository.Factory, private val filter: FilterCoordinator, - private val tagHighlighter: MangaTagHighlighter, settings: AppSettings, listExtraProvider: ListExtraProvider, downloadScheduler: DownloadWorker.Scheduler, @@ -72,7 +70,7 @@ open class RemoteListViewModel @Inject constructor( list == null -> add(LoadingState) list.isEmpty() -> add(createEmptyState(header.value.hasSelectedTags)) else -> { - list.toUi(this, mode, listExtraProvider, tagHighlighter) + list.toUi(this, mode, listExtraProvider) when { error != null -> add(error.toErrorFooter()) hasNext -> add(LoadingFooter()) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt index ff7abf11c..a1ad1f52a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt @@ -13,10 +13,10 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaRepository -import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.download.ui.worker.DownloadWorker +import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel @@ -33,7 +33,7 @@ class SearchViewModel @Inject constructor( savedStateHandle: SavedStateHandle, repositoryFactory: MangaRepository.Factory, settings: AppSettings, - private val tagHighlighter: MangaTagHighlighter, + private val extraProvider: ListExtraProvider, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { @@ -64,7 +64,7 @@ class SearchViewModel @Inject constructor( else -> { val result = ArrayList(list.size + 1) - list.toUi(result, mode, tagHighlighter) + list.toUi(result, mode, extraProvider) when { error != null -> result += error.toErrorFooter() hasNext -> result += LoadingFooter() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt index 51a273537..f117f6d09 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt @@ -25,6 +25,7 @@ import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.download.ui.worker.DownloadWorker +import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingFooter @@ -42,6 +43,7 @@ private const val MIN_HAS_MORE_ITEMS = 8 @HiltViewModel class MultiSearchViewModel @Inject constructor( savedStateHandle: SavedStateHandle, + private val extraProvider: ListExtraProvider, private val settings: AppSettings, private val mangaRepositoryFactory: MangaRepository.Factory, private val downloadScheduler: DownloadWorker.Scheduler, @@ -128,7 +130,7 @@ class MultiSearchViewModel @Inject constructor( async(dispatcher) { runCatchingCancellable { val list = mangaRepositoryFactory.create(source).getList(offset = 0, query = q) - .toUi(ListMode.GRID, null) + .toUi(ListMode.GRID, extraProvider) if (list.isNotEmpty()) { MultiSearchListModel(source, list.size > MIN_HAS_MORE_ITEMS, list) } else { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContentObserveUseCase.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContentObserveUseCase.kt index 5fa916e1c..b2104c199 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContentObserveUseCase.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContentObserveUseCase.kt @@ -25,6 +25,7 @@ import org.koitharu.kotatsu.suggestions.domain.SuggestionRepository import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject +@Suppress("SameParameterValue") class ShelfContentObserveUseCase @Inject constructor( private val localMangaRepository: LocalMangaRepository, private val historyRepository: HistoryRepository, @@ -35,20 +36,20 @@ class ShelfContentObserveUseCase @Inject constructor( ) { operator fun invoke(): Flow = combine( - historyRepository.observeAllWithHistory(), - observeLocalManga(SortOrder.UPDATED), + historyRepository.observeAll(20), + observeLocalManga(SortOrder.UPDATED, 20), observeFavourites(), trackingRepository.observeUpdatedManga(), - suggestionRepository.observeAll(16), + suggestionRepository.observeAll(20), ) { history, local, favorites, updated, suggestions -> ShelfContent(history, favorites, updated, local, suggestions) } - private fun observeLocalManga(sortOrder: SortOrder): Flow> { + private fun observeLocalManga(sortOrder: SortOrder, limit: Int): Flow> { return localStorageChanges .onStart { emit(null) } .mapLatest { - localMangaRepository.getList(0, null, sortOrder) + localMangaRepository.getList(0, null, sortOrder).take(limit) }.distinctUntilChanged() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfContent.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfContent.kt index 3e98c8cd3..39c88010f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfContent.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfContent.kt @@ -1,13 +1,12 @@ package org.koitharu.kotatsu.shelf.domain.model import org.koitharu.kotatsu.core.model.FavouriteCategory -import org.koitharu.kotatsu.history.domain.model.MangaWithHistory import org.koitharu.kotatsu.parsers.model.Manga class ShelfContent( - val history: List, + val history: List, val favourites: Map>, - val updated: Map, + val updated: List, val local: List, val suggestions: List, ) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt index 557801d47..16ea86002 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt @@ -23,8 +23,6 @@ import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.history.data.HistoryRepository -import org.koitharu.kotatsu.history.data.PROGRESS_NONE -import org.koitharu.kotatsu.history.domain.model.MangaWithHistory import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.model.EmptyHint import org.koitharu.kotatsu.list.ui.model.EmptyState @@ -41,21 +39,20 @@ import org.koitharu.kotatsu.shelf.domain.model.ShelfContent import org.koitharu.kotatsu.shelf.domain.model.ShelfSection import org.koitharu.kotatsu.shelf.ui.model.ShelfSectionModel import org.koitharu.kotatsu.sync.domain.SyncController -import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject @HiltViewModel class ShelfViewModel @Inject constructor( private val historyRepository: HistoryRepository, private val favouritesRepository: FavouritesRepository, - private val trackingRepository: TrackingRepository, private val settings: AppSettings, private val downloadScheduler: DownloadWorker.Scheduler, private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase, + private val listExtraProvider: ListExtraProvider, shelfContentObserveUseCase: ShelfContentObserveUseCase, syncController: SyncController, networkState: NetworkState, -) : BaseViewModel(), ListExtraProvider { +) : BaseViewModel() { val onActionDone = MutableEventFlow() val onDownloadStarted = MutableEventFlow() @@ -78,22 +75,6 @@ class ShelfViewModel @Inject constructor( } } - override suspend fun getCounter(mangaId: Long): Int { - return if (settings.isTrackerEnabled) { - trackingRepository.getNewChaptersCount(mangaId) - } else { - 0 - } - } - - override suspend fun getProgress(mangaId: Long): Float { - return if (settings.isReadingIndicatorsEnabled) { - historyRepository.getProgress(mangaId) - } else { - PROGRESS_NONE - } - } - fun removeFromFavourites(category: FavouriteCategory, ids: Set) { if (ids.isEmpty()) { return @@ -194,7 +175,7 @@ class ShelfViewModel @Inject constructor( when (section) { ShelfSection.HISTORY -> mapHistory( result, - content.history.filter { it.manga.source == MangaSource.LOCAL }, + content.history.filter { it.source == MangaSource.LOCAL }, ) ShelfSection.LOCAL -> mapLocal(result, content.local) @@ -222,17 +203,14 @@ class ShelfViewModel @Inject constructor( private suspend fun mapHistory( destination: MutableList, - list: List, + list: List, ) { if (list.isEmpty()) { return } - val showPercent = settings.isReadingIndicatorsEnabled destination += ShelfSectionModel.History( - items = list.map { (manga, history) -> - val counter = getCounter(manga.id) - val percent = if (showPercent) history.percent else PROGRESS_NONE - manga.toGridModel(counter, percent) + items = list.map { manga -> + manga.toGridModel(listExtraProvider) }, showAllButtonText = R.string.show_all, ) @@ -240,16 +218,15 @@ class ShelfViewModel @Inject constructor( private suspend fun mapUpdated( destination: MutableList, - updated: Map, + updated: List, ) { if (updated.isEmpty()) { return } - val showPercent = settings.isReadingIndicatorsEnabled + settings.isReadingIndicatorsEnabled destination += ShelfSectionModel.Updated( - items = updated.map { (manga, counter) -> - val percent = if (showPercent) getProgress(manga.id) else PROGRESS_NONE - manga.toGridModel(counter, percent) + items = updated.map { manga -> + manga.toGridModel(listExtraProvider) }, showAllButtonText = R.string.show_all, ) @@ -263,7 +240,7 @@ class ShelfViewModel @Inject constructor( return } destination += ShelfSectionModel.Local( - items = local.toUi(ListMode.GRID, this, null), + items = local.toUi(ListMode.GRID, listExtraProvider), showAllButtonText = R.string.show_all, ) } @@ -276,7 +253,7 @@ class ShelfViewModel @Inject constructor( return } destination += ShelfSectionModel.Suggestions( - items = suggestions.toUi(ListMode.GRID, this, null), + items = suggestions.toUi(ListMode.GRID, listExtraProvider), showAllButtonText = R.string.show_all, ) } @@ -291,7 +268,7 @@ class ShelfViewModel @Inject constructor( for ((category, list) in favourites) { if (list.isNotEmpty()) { destination += ShelfSectionModel.Favourites( - items = list.toUi(ListMode.GRID, this, null), + items = list.toUi(ListMode.GRID, listExtraProvider), category = category, showAllButtonText = R.string.show_all, ) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt index 5eff7818f..40338a217 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt @@ -10,10 +10,10 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.ext.onFirst import org.koitharu.kotatsu.download.ui.worker.DownloadWorker +import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.LoadingState @@ -26,7 +26,7 @@ import javax.inject.Inject class SuggestionsViewModel @Inject constructor( repository: SuggestionRepository, settings: AppSettings, - private val tagHighlighter: MangaTagHighlighter, + private val extraProvider: ListExtraProvider, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { @@ -44,7 +44,7 @@ class SuggestionsViewModel @Inject constructor( ), ) - else -> list.toUi(mode, tagHighlighter) + else -> list.toUi(mode, extraProvider) } }.onStart { loadingCounter.increment() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/TracksDao.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/TracksDao.kt index 0915582a1..bd9b03a83 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/TracksDao.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/TracksDao.kt @@ -34,9 +34,8 @@ abstract class TracksDao { abstract fun observeNewChapters(mangaId: Long): Flow @Transaction - @MapInfo(valueColumn = "chapters_new") - @Query("SELECT manga.*, chapters_new FROM tracks LEFT JOIN manga ON manga.manga_id = tracks.manga_id WHERE chapters_new > 0 ORDER BY chapters_new DESC") - abstract fun observeUpdatedManga(): Flow> + @Query("SELECT manga.* FROM tracks LEFT JOIN manga ON manga.manga_id = tracks.manga_id WHERE chapters_new > 0 ORDER BY chapters_new DESC") + abstract fun observeUpdatedManga(): Flow> @Query("DELETE FROM tracks") abstract suspend fun clear() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt index a6b3b8518..482b25fa1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt @@ -12,6 +12,7 @@ import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.entity.MangaEntity import org.koitharu.kotatsu.core.db.entity.toManga import org.koitharu.kotatsu.core.model.FavouriteCategory +import org.koitharu.kotatsu.core.util.ext.mapItems import org.koitharu.kotatsu.favourites.data.toFavouriteCategory import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource @@ -44,9 +45,9 @@ class TrackingRepository @Inject constructor( return db.tracksDao.observeNewChapters().map { list -> list.count { it > 0 } } } - fun observeUpdatedManga(): Flow> { + fun observeUpdatedManga(): Flow> { return db.tracksDao.observeUpdatedManga() - .map { x -> x.mapKeys { it.key.toManga() } } + .mapItems { it.toManga() } .distinctUntilChanged() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt index a3dffc059..a8c437c6b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt @@ -10,22 +10,16 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.util.ext.onFirst import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.history.data.HistoryRepository -import org.koitharu.kotatsu.history.data.PROGRESS_NONE +import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState -import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingState import org.koitharu.kotatsu.list.ui.model.toErrorState -import org.koitharu.kotatsu.list.ui.model.toGridModel -import org.koitharu.kotatsu.list.ui.model.toListDetailedModel -import org.koitharu.kotatsu.list.ui.model.toListModel -import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.list.ui.model.toUi import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject @@ -34,16 +28,16 @@ class UpdatesViewModel @Inject constructor( private val repository: TrackingRepository, private val settings: AppSettings, private val historyRepository: HistoryRepository, - private val tagHighlighter: MangaTagHighlighter, + private val extraProvider: ListExtraProvider, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { override val content = combine( repository.observeUpdatedManga(), listMode, - ) { mangaMap, mode -> + ) { mangaList, mode -> when { - mangaMap.isEmpty() -> listOf( + mangaList.isEmpty() -> listOf( EmptyState( icon = R.drawable.ic_empty_history, textPrimary = R.string.text_history_holder_primary, @@ -52,7 +46,7 @@ class UpdatesViewModel @Inject constructor( ), ) - else -> mapList(mangaMap, mode) + else -> mangaList.toUi(mode, extraProvider) } }.onStart { loadingCounter.increment() @@ -65,19 +59,4 @@ class UpdatesViewModel @Inject constructor( override fun onRefresh() = Unit override fun onRetry() = Unit - - private suspend fun mapList( - mangaMap: Map, - mode: ListMode, - ): List { - val showPercent = settings.isReadingIndicatorsEnabled - return mangaMap.map { (manga, counter) -> - val percent = if (showPercent) historyRepository.getProgress(manga.id) else PROGRESS_NONE - when (mode) { - ListMode.LIST -> manga.toListModel(counter, percent) - ListMode.DETAILED_LIST -> manga.toListDetailedModel(counter, percent, tagHighlighter) - ListMode.GRID -> manga.toGridModel(counter, percent) - } - } - } } From c2ee548f0a091466dabce0ed065546c5dfb60399 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 5 Jun 2023 09:34:56 +0300 Subject: [PATCH 35/94] Show errors in global search results --- .../search/ui/multi/MultiSearchListModel.kt | 7 +-- .../search/ui/multi/MultiSearchViewModel.kt | 54 +++++++------------ .../ui/multi/adapter/SearchResultsAD.kt | 5 ++ app/src/main/res/drawable/ic_error_small.xml | 11 ++++ app/src/main/res/layout/item_list_group.xml | 19 ++++++- 5 files changed, 58 insertions(+), 38 deletions(-) create mode 100644 app/src/main/res/drawable/ic_error_small.xml diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchListModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchListModel.kt index f8801ca11..8f6ed856e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchListModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchListModel.kt @@ -8,6 +8,7 @@ class MultiSearchListModel( val source: MangaSource, val hasMore: Boolean, val list: List, + val error: Throwable?, ) : ListModel { override fun equals(other: Any?): Boolean { @@ -19,14 +20,14 @@ class MultiSearchListModel( if (source != other.source) return false if (hasMore != other.hasMore) return false if (list != other.list) return false - - return true + return error == other.error } override fun hashCode(): Int { var result = source.hashCode() result = 31 * result + hasMore.hashCode() result = 31 * result + list.hashCode() + result = 31 * result + (error?.hashCode() ?: 0) return result } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt index f117f6d09..2f4615796 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt @@ -16,8 +16,8 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.plus +import kotlinx.coroutines.withTimeout import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.exceptions.CompositeException import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ListMode @@ -30,7 +30,6 @@ import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingFooter import org.koitharu.kotatsu.list.ui.model.LoadingState -import org.koitharu.kotatsu.list.ui.model.toErrorState import org.koitharu.kotatsu.list.ui.model.toUi import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.util.runCatchingCancellable @@ -52,20 +51,17 @@ class MultiSearchViewModel @Inject constructor( private var searchJob: Job? = null private val listData = MutableStateFlow>(emptyList()) private val loadingData = MutableStateFlow(false) - private var listError = MutableStateFlow(null) val onDownloadStarted = MutableEventFlow() val query = MutableStateFlow(savedStateHandle.get(MultiSearchActivity.EXTRA_QUERY).orEmpty()) val list: StateFlow> = combine( listData, loadingData, - listError, - ) { list, loading, error -> + ) { list, loading -> when { list.isEmpty() -> listOf( when { loading -> LoadingState - error != null -> error.toErrorState(canRetry = true) else -> EmptyState( icon = R.drawable.ic_empty_common, textPrimary = R.string.nothing_found, @@ -101,15 +97,12 @@ class MultiSearchViewModel @Inject constructor( searchJob = launchJob(Dispatchers.Default) { prevJob?.cancelAndJoin() try { - listError.value = null listData.value = emptyList() loadingData.value = true query.value = q searchImpl(q) } catch (e: CancellationException) { throw e - } catch (e: Throwable) { - listError.value = e } finally { loadingData.value = false } @@ -129,35 +122,28 @@ class MultiSearchViewModel @Inject constructor( val deferredList = sources.map { source -> async(dispatcher) { runCatchingCancellable { - val list = mangaRepositoryFactory.create(source).getList(offset = 0, query = q) - .toUi(ListMode.GRID, extraProvider) - if (list.isNotEmpty()) { - MultiSearchListModel(source, list.size > MIN_HAS_MORE_ITEMS, list) - } else { - null + withTimeout(8_000) { + mangaRepositoryFactory.create(source).getList(offset = 0, query = q) + .toUi(ListMode.GRID, extraProvider) } - }.onFailure { - it.printStackTraceDebug() - } + }.fold( + onSuccess = { list -> + if (list.isEmpty()) { + null + } else { + MultiSearchListModel(source, list.size > MIN_HAS_MORE_ITEMS, list, null) + } + }, + onFailure = { error -> + error.printStackTraceDebug() + MultiSearchListModel(source, true, emptyList(), error) + }, + ) } } - - val errors = ArrayList() for (deferred in deferredList) { - deferred.await() - .onSuccess { item -> - if (item != null) { - listData.update { x -> x + item } - } - }.onFailure { - errors.add(it) - } - } - if (listData.value.isEmpty()) { - when (errors.size) { - 0 -> Unit - 1 -> throw errors[0] - else -> throw CompositeException(errors) + deferred.await()?.let { item -> + listData.update { x -> x + item } } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/SearchResultsAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/SearchResultsAD.kt index 2fdcf1b90..9bd049052 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/SearchResultsAD.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/SearchResultsAD.kt @@ -1,5 +1,6 @@ package org.koitharu.kotatsu.search.ui.multi.adapter +import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.RecyclerView.RecycledViewPool @@ -10,6 +11,8 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration +import org.koitharu.kotatsu.core.util.ext.getDisplayMessage +import org.koitharu.kotatsu.core.util.ext.textAndVisible import org.koitharu.kotatsu.databinding.ItemListGroupBinding import org.koitharu.kotatsu.list.ui.ItemSizeResolver import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration @@ -46,5 +49,7 @@ fun searchResultsAD( binding.buttonMore.isVisible = item.hasMore adapter.notifyDataSetChanged() adapter.items = item.list + binding.recyclerView.isGone = item.list.isEmpty() + binding.textViewError.textAndVisible = item.error?.getDisplayMessage(context.resources) } } diff --git a/app/src/main/res/drawable/ic_error_small.xml b/app/src/main/res/drawable/ic_error_small.xml new file mode 100644 index 000000000..964da43cc --- /dev/null +++ b/app/src/main/res/drawable/ic_error_small.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/layout/item_list_group.xml b/app/src/main/res/layout/item_list_group.xml index 998d7d74e..3a8becad9 100644 --- a/app/src/main/res/layout/item_list_group.xml +++ b/app/src/main/res/layout/item_list_group.xml @@ -47,4 +47,21 @@ android:paddingHorizontal="@dimen/grid_spacing" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> - \ No newline at end of file + + + From 6dc460bc20f93b059cbc2b4deeb4feb4c1d16e6c Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 5 Jun 2023 10:45:23 +0300 Subject: [PATCH 36/94] Replace CloudFlareDialog with activity --- app/src/main/AndroidManifest.xml | 4 + .../kotatsu/browser/BrowserActivity.kt | 1 + .../browser/cloudflare/CloudFlareActivity.kt | 175 ++++++++++++++++++ .../browser/cloudflare/CloudFlareDialog.kt | 123 ------------ .../exceptions/resolve/ExceptionResolver.kt | 45 ++--- .../kotatsu/core/ui/AlertDialogFragment.kt | 1 + .../kotatsu/core/util/TaggedActivityResult.kt | 7 +- .../koitharu/kotatsu/core/util/ext/String.kt | 2 +- .../main/res/layout/fragment_cloudflare.xml | 21 --- 9 files changed, 204 insertions(+), 175 deletions(-) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CloudFlareActivity.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt delete mode 100644 app/src/main/res/layout/fragment_cloudflare.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 10faa7ae2..2a167d459 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -102,6 +102,10 @@ android:name="org.koitharu.kotatsu.browser.BrowserActivity" android:configChanges="orientation|screenSize|screenLayout|keyboardHidden" android:windowSoftInputMode="adjustResize" /> + (), BrowserCallback override fun onDestroy() { super.onDestroy() + viewBinding.webView.stopLoading() viewBinding.webView.destroy() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CloudFlareActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CloudFlareActivity.kt new file mode 100644 index 000000000..51d29fc9f --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CloudFlareActivity.kt @@ -0,0 +1,175 @@ +package org.koitharu.kotatsu.browser.cloudflare + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.view.MenuItem +import android.webkit.CookieManager +import android.webkit.WebSettings +import androidx.activity.result.contract.ActivityResultContract +import androidx.core.graphics.Insets +import androidx.core.net.toUri +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import androidx.core.view.updatePadding +import dagger.hilt.android.AndroidEntryPoint +import okhttp3.Headers +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.browser.WebViewBackPressedCallback +import org.koitharu.kotatsu.core.network.CommonHeaders +import org.koitharu.kotatsu.core.network.CommonHeadersInterceptor +import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar +import org.koitharu.kotatsu.core.ui.BaseActivity +import org.koitharu.kotatsu.core.util.TaggedActivityResult +import org.koitharu.kotatsu.core.util.ext.catchingWebViewUnavailability +import org.koitharu.kotatsu.databinding.ActivityBrowserBinding +import javax.inject.Inject +import com.google.android.material.R as materialR + +@AndroidEntryPoint +class CloudFlareActivity : BaseActivity(), CloudFlareCallback { + + private var pendingResult = RESULT_CANCELED + + @Inject + lateinit var cookieJar: MutableCookieJar + + private var onBackPressedCallback: WebViewBackPressedCallback? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (!catchingWebViewUnavailability { setContentView(ActivityBrowserBinding.inflate(layoutInflater)) }) { + return + } + supportActionBar?.run { + setDisplayHomeAsUpEnabled(true) + setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material) + } + val url = intent?.dataString.orEmpty() + with(viewBinding.webView.settings) { + javaScriptEnabled = true + cacheMode = WebSettings.LOAD_DEFAULT + domStorageEnabled = true + databaseEnabled = true + userAgentString = intent?.getStringExtra(ARG_UA) ?: CommonHeadersInterceptor.userAgentFallback + } + viewBinding.webView.webViewClient = CloudFlareClient(cookieJar, this, url) + onBackPressedCallback = WebViewBackPressedCallback(viewBinding.webView).also { + onBackPressedDispatcher.addCallback(it) + } + CookieManager.getInstance().setAcceptThirdPartyCookies(viewBinding.webView, true) + if (savedInstanceState != null) { + return + } + if (url.isEmpty()) { + finishAfterTransition() + } else { + onTitleChanged(getString(R.string.loading_), url) + viewBinding.webView.loadUrl(url) + } + } + + override fun onDestroy() { + viewBinding.webView.run { + stopLoading() + destroy() + } + super.onDestroy() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + viewBinding.webView.saveState(outState) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle) { + super.onRestoreInstanceState(savedInstanceState) + viewBinding.webView.restoreState(savedInstanceState) + } + + override fun onWindowInsetsChanged(insets: Insets) { + viewBinding.appbar.updatePadding( + top = insets.top, + ) + viewBinding.root.updatePadding( + left = insets.left, + right = insets.right, + bottom = insets.bottom, + ) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { + android.R.id.home -> { + viewBinding.webView.stopLoading() + finishAfterTransition() + true + } + + else -> super.onOptionsItemSelected(item) + } + + override fun onResume() { + super.onResume() + viewBinding.webView.onResume() + } + + override fun onPause() { + viewBinding.webView.onPause() + super.onPause() + } + + override fun finish() { + setResult(pendingResult) + super.finish() + } + + override fun onPageLoaded() { + viewBinding.progressBar.isInvisible = true + } + + override fun onCheckPassed() { + pendingResult = RESULT_OK + finishAfterTransition() + } + + override fun onLoadingStateChanged(isLoading: Boolean) { + viewBinding.progressBar.isVisible = isLoading + } + + override fun onHistoryChanged() { + onBackPressedCallback?.onHistoryChanged() + } + + override fun onTitleChanged(title: CharSequence, subtitle: CharSequence?) { + setTitle(title) + supportActionBar?.subtitle = subtitle?.toString()?.toHttpUrlOrNull()?.topPrivateDomain() ?: subtitle + } + + class Contract : ActivityResultContract, TaggedActivityResult>() { + override fun createIntent(context: Context, input: Pair): Intent { + return newIntent(context, input.first, input.second) + } + + override fun parseResult(resultCode: Int, intent: Intent?): TaggedActivityResult { + return TaggedActivityResult(TAG, resultCode) + } + } + + companion object { + + const val TAG = "CloudFlareActivity" + private const val ARG_UA = "ua" + + fun newIntent( + context: Context, + url: String, + headers: Headers?, + ) = Intent(context, CloudFlareActivity::class.java).apply { + data = url.toUri() + headers?.get(CommonHeaders.USER_AGENT)?.let { + putExtra(ARG_UA, it) + } + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt b/app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt deleted file mode 100644 index 0a1284448..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt +++ /dev/null @@ -1,123 +0,0 @@ -package org.koitharu.kotatsu.browser.cloudflare - -import android.content.DialogInterface -import android.os.Bundle -import android.view.LayoutInflater -import android.view.ViewGroup -import android.webkit.CookieManager -import android.webkit.WebSettings -import androidx.appcompat.app.AlertDialog -import androidx.core.view.isInvisible -import androidx.fragment.app.setFragmentResult -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import dagger.hilt.android.AndroidEntryPoint -import okhttp3.Headers -import org.koitharu.kotatsu.browser.WebViewBackPressedCallback -import org.koitharu.kotatsu.core.network.CommonHeaders -import org.koitharu.kotatsu.core.network.CommonHeadersInterceptor -import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar -import org.koitharu.kotatsu.core.ui.AlertDialogFragment -import org.koitharu.kotatsu.core.util.ext.withArgs -import org.koitharu.kotatsu.databinding.FragmentCloudflareBinding -import javax.inject.Inject - -@AndroidEntryPoint -class CloudFlareDialog : AlertDialogFragment(), CloudFlareCallback { - - private lateinit var url: String - private val pendingResult = Bundle(1) - - @Inject - lateinit var cookieJar: MutableCookieJar - - private var onBackPressedCallback: WebViewBackPressedCallback? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - url = requireArguments().getString(ARG_URL).orEmpty() - } - - override fun onCreateViewBinding( - inflater: LayoutInflater, - container: ViewGroup?, - ) = FragmentCloudflareBinding.inflate(inflater, container, false) - - override fun onViewBindingCreated(binding: FragmentCloudflareBinding, savedInstanceState: Bundle?) { - super.onViewBindingCreated(binding, savedInstanceState) - with(binding.webView.settings) { - javaScriptEnabled = true - cacheMode = WebSettings.LOAD_DEFAULT - domStorageEnabled = true - databaseEnabled = true - userAgentString = arguments?.getString(ARG_UA) ?: CommonHeadersInterceptor.userAgentChrome - } - binding.webView.webViewClient = CloudFlareClient(cookieJar, this, url) - CookieManager.getInstance().setAcceptThirdPartyCookies(binding.webView, true) - if (url.isEmpty()) { - dismissAllowingStateLoss() - } else { - binding.webView.loadUrl(url) - } - } - - override fun onDestroyView() { - requireViewBinding().webView.stopLoading() - requireViewBinding().webView.destroy() - onBackPressedCallback = null - super.onDestroyView() - } - - override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { - return super.onBuildDialog(builder).setNegativeButton(android.R.string.cancel, null) - } - - override fun onDialogCreated(dialog: AlertDialog) { - super.onDialogCreated(dialog) - onBackPressedCallback = WebViewBackPressedCallback(requireViewBinding().webView).also { - dialog.onBackPressedDispatcher.addCallback(it) - } - } - - override fun onResume() { - super.onResume() - requireViewBinding().webView.onResume() - } - - override fun onPause() { - requireViewBinding().webView.onPause() - super.onPause() - } - - override fun onDismiss(dialog: DialogInterface) { - setFragmentResult(TAG, pendingResult) - super.onDismiss(dialog) - } - - override fun onPageLoaded() { - viewBinding?.progressBar?.isInvisible = true - } - - override fun onCheckPassed() { - pendingResult.putBoolean(EXTRA_RESULT, true) - dismissAllowingStateLoss() - } - - override fun onHistoryChanged() { - onBackPressedCallback?.onHistoryChanged() - } - - companion object { - - const val TAG = "CloudFlareDialog" - const val EXTRA_RESULT = "result" - private const val ARG_URL = "url" - private const val ARG_UA = "ua" - - fun newInstance(url: String, headers: Headers?) = CloudFlareDialog().withArgs(2) { - putString(ARG_URL, url) - headers?.get(CommonHeaders.USER_AGENT)?.let { - putString(ARG_UA, it) - } - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt index b5e267dcb..9407ab6e9 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt @@ -6,15 +6,13 @@ import androidx.annotation.StringRes import androidx.collection.ArrayMap import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity -import kotlinx.coroutines.suspendCancellableCoroutine import okhttp3.Headers import org.koitharu.kotatsu.R import org.koitharu.kotatsu.browser.BrowserActivity -import org.koitharu.kotatsu.browser.cloudflare.CloudFlareDialog +import org.koitharu.kotatsu.browser.cloudflare.CloudFlareActivity import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog import org.koitharu.kotatsu.core.util.TaggedActivityResult -import org.koitharu.kotatsu.core.util.isSuccess import org.koitharu.kotatsu.parsers.exception.AuthRequiredException import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.model.MangaSource @@ -23,20 +21,26 @@ import kotlin.coroutines.Continuation import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine -class ExceptionResolver private constructor( - private val activity: FragmentActivity?, - private val fragment: Fragment?, -) : ActivityResultCallback { +class ExceptionResolver : ActivityResultCallback { private val continuations = ArrayMap>(1) - private lateinit var sourceAuthContract: ActivityResultLauncher - - constructor(activity: FragmentActivity) : this(activity = activity, fragment = null) { + private val activity: FragmentActivity? + private val fragment: Fragment? + private val sourceAuthContract: ActivityResultLauncher + private val cloudflareContract: ActivityResultLauncher> + + constructor(activity: FragmentActivity) { + this.activity = activity + fragment = null sourceAuthContract = activity.registerForActivityResult(SourceAuthActivity.Contract(), this) + cloudflareContract = activity.registerForActivityResult(CloudFlareActivity.Contract(), this) } - constructor(fragment: Fragment) : this(activity = null, fragment = fragment) { + constructor(fragment: Fragment) { + this.fragment = fragment + activity = null sourceAuthContract = fragment.registerForActivityResult(SourceAuthActivity.Contract(), this) + cloudflareContract = fragment.registerForActivityResult(CloudFlareActivity.Contract(), this) } override fun onActivityResult(result: TaggedActivityResult) { @@ -58,22 +62,9 @@ class ExceptionResolver private constructor( else -> false } - private suspend fun resolveCF(url: String, headers: Headers): Boolean { - val dialog = CloudFlareDialog.newInstance(url, headers) - val fm = getFragmentManager() - return suspendCancellableCoroutine { cont -> - fm.clearFragmentResult(CloudFlareDialog.TAG) - continuations[CloudFlareDialog.TAG] = cont - fm.setFragmentResultListener(CloudFlareDialog.TAG, checkNotNull(fragment ?: activity)) { key, result -> - continuations.remove(key)?.resume(result.getBoolean(CloudFlareDialog.EXTRA_RESULT)) - } - dialog.show(fm, CloudFlareDialog.TAG) - cont.invokeOnCancellation { - continuations.remove(CloudFlareDialog.TAG, cont) - fm.clearFragmentResultListener(CloudFlareDialog.TAG) - dialog.dismissAllowingStateLoss() - } - } + private suspend fun resolveCF(url: String, headers: Headers): Boolean = suspendCoroutine { cont -> + continuations[CloudFlareActivity.TAG] = cont + cloudflareContract.launch(url to headers) } private suspend fun resolveAuthException(source: MangaSource): Boolean = suspendCoroutine { cont -> diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/AlertDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/AlertDialogFragment.kt index 40c091d4d..6809043ef 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/AlertDialogFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/AlertDialogFragment.kt @@ -27,6 +27,7 @@ abstract class AlertDialogFragment : DialogFragment() { .setView(binding.root) .run(::onBuildDialog) .create() + .also(::onDialogCreated) } final override fun onCreateView( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/TaggedActivityResult.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/TaggedActivityResult.kt index 8fba053eb..c55aaa121 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/TaggedActivityResult.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/TaggedActivityResult.kt @@ -5,7 +5,8 @@ import android.app.Activity class TaggedActivityResult( val tag: String, val result: Int, -) +) { -val TaggedActivityResult.isSuccess: Boolean - get() = this.result == Activity.RESULT_OK + val isSuccess: Boolean + get() = result == Activity.RESULT_OK +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/String.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/String.kt index bc43c656e..e418d1d1b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/String.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/String.kt @@ -5,7 +5,7 @@ import org.koitharu.kotatsu.parsers.util.levenshteinDistance import org.koitharu.kotatsu.util.ext.printStackTraceDebug import java.util.UUID -inline fun String?.ifNullOrEmpty(defaultValue: () -> String): String { +inline fun C?.ifNullOrEmpty(defaultValue: () -> C): C { return if (this.isNullOrEmpty()) defaultValue() else this } diff --git a/app/src/main/res/layout/fragment_cloudflare.xml b/app/src/main/res/layout/fragment_cloudflare.xml deleted file mode 100644 index 91a115312..000000000 --- a/app/src/main/res/layout/fragment_cloudflare.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - \ No newline at end of file From 76709dda21d136b623600094b417db95bc9a0922 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 5 Jun 2023 10:57:35 +0300 Subject: [PATCH 37/94] Remove replacement characters from manga description --- .../kotlin/org/koitharu/kotatsu/core/util/ext/String.kt | 6 ++++++ .../org/koitharu/kotatsu/details/ui/DetailsViewModel.kt | 3 ++- .../kotatsu/details/ui/scrobbling/ScrobblingInfoSheet.kt | 3 ++- .../koitharu/kotatsu/scrobbling/common/domain/Scrobbler.kt | 3 ++- .../koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt | 3 ++- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/String.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/String.kt index e418d1d1b..bc09b90f3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/String.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/String.kt @@ -35,3 +35,9 @@ fun String.almostEquals(other: String, @FloatRange(from = 0.0) threshold: Float) val diff = lowercase().levenshteinDistance(other.lowercase()) / ((length + other.length) / 2f) return diff < threshold } + +fun CharSequence.sanitize(): CharSequence { + return filterNot { c -> c.isReplacement() } +} + +fun Char.isReplacement() = this in '\uFFF0'..'\uFFFF' diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt index 0c5c13484..ab56e71f6 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt @@ -37,6 +37,7 @@ import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.computeSize import org.koitharu.kotatsu.core.util.ext.requireValue +import org.koitharu.kotatsu.core.util.ext.sanitize import org.koitharu.kotatsu.core.util.ext.toFileOrNull import org.koitharu.kotatsu.details.domain.BranchComparator import org.koitharu.kotatsu.details.domain.DetailsInteractor @@ -135,7 +136,7 @@ class DetailsViewModel @Inject constructor( if (description.isNullOrEmpty()) { emit(null) } else { - emit(description.parseAsHtml().filterSpans()) + emit(description.parseAsHtml().filterSpans().sanitize()) emit(description.parseAsHtml(imageGetter = imageGetter).filterSpans()) } }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.WhileSubscribed(5000), null) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/scrobbling/ScrobblingInfoSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/scrobbling/ScrobblingInfoSheet.kt index 7578154e1..34a5f8332 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/scrobbling/ScrobblingInfoSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/scrobbling/ScrobblingInfoSheet.kt @@ -23,6 +23,7 @@ import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.newImageRequest import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observeEvent +import org.koitharu.kotatsu.core.util.ext.sanitize import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.databinding.SheetScrobblingBinding @@ -122,7 +123,7 @@ class ScrobblingInfoSheet : } requireViewBinding().textViewTitle.text = scrobbling.title requireViewBinding().ratingBar.rating = scrobbling.rating * requireViewBinding().ratingBar.numStars - requireViewBinding().textViewDescription.text = scrobbling.description + requireViewBinding().textViewDescription.text = scrobbling.description?.sanitize() requireViewBinding().spinnerStatus.setSelection(scrobbling.status?.ordinal ?: -1) requireViewBinding().imageViewLogo.contentDescription = getString(scrobbling.scrobbler.titleResId) requireViewBinding().imageViewLogo.setImageResource(scrobbling.scrobbler.iconResId) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/domain/Scrobbler.kt b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/domain/Scrobbler.kt index 3cd124561..44251693e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/domain/Scrobbler.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/scrobbling/common/domain/Scrobbler.kt @@ -11,6 +11,7 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.util.ext.findKeyByValue +import org.koitharu.kotatsu.core.util.ext.sanitize import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.scrobbling.common.data.ScrobblingEntity @@ -123,7 +124,7 @@ abstract class Scrobbler( rating = rating, title = mangaInfo.name, coverUrl = mangaInfo.cover, - description = mangaInfo.descriptionHtml.parseAsHtml(), + description = mangaInfo.descriptionHtml.parseAsHtml().sanitize(), externalUrl = mangaInfo.url, ) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt index e5770a597..d58db1e4c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt @@ -41,6 +41,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.ext.almostEquals import org.koitharu.kotatsu.core.util.ext.asArrayList import org.koitharu.kotatsu.core.util.ext.flatten +import org.koitharu.kotatsu.core.util.ext.sanitize import org.koitharu.kotatsu.core.util.ext.takeMostFrequent import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull import org.koitharu.kotatsu.core.util.ext.trySetForeground @@ -227,7 +228,7 @@ class SuggestionsWorker @AssistedInject constructor( ).toBitmapOrNull(), ) setSmallIcon(R.drawable.ic_stat_suggestion) - val description = manga.description?.parseAsHtml(HtmlCompat.FROM_HTML_MODE_COMPACT) + val description = manga.description?.parseAsHtml(HtmlCompat.FROM_HTML_MODE_COMPACT)?.sanitize() if (!description.isNullOrBlank()) { val style = NotificationCompat.BigTextStyle() style.bigText( From e794f84c6f83824afc7a0cb2aab368b7a678c78f Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 5 Jun 2023 11:52:56 +0300 Subject: [PATCH 38/94] Get rid of SlidingPaneLayout in settings --- .../kotatsu/core/ui/BasePreferenceFragment.kt | 10 ++-- .../kotatsu/settings/SettingsActivity.kt | 44 +++++++++++------ .../settings/SettingsHeadersFragment.kt | 49 ------------------- .../settings/sources/SourcesListFragment.kt | 4 +- .../res/layout-w600dp/activity_settings.xml | 46 +++++++++++++---- app/src/main/res/layout/activity_settings.xml | 3 +- 6 files changed, 74 insertions(+), 82 deletions(-) delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsHeadersFragment.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt index bfffb7ab3..ce040a63e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt @@ -9,10 +9,10 @@ import androidx.core.view.updatePadding import androidx.preference.PreferenceFragmentCompat import androidx.recyclerview.widget.RecyclerView import dagger.hilt.android.AndroidEntryPoint +import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner import org.koitharu.kotatsu.core.ui.util.WindowInsetsDelegate -import org.koitharu.kotatsu.settings.SettingsHeadersFragment import javax.inject.Inject @Suppress("LeakingThis") @@ -56,9 +56,11 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : ) } - @Suppress("UsePropertyAccessSyntax") protected fun setTitle(title: CharSequence) { - (parentFragment as? SettingsHeadersFragment)?.setTitle(title) - ?: activity?.setTitle(title) + activity?.let { + if (!it.resources.getBoolean(R.bool.is_tablet)) { + it.title = title + } + } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt index 9b608aa96..366cd8c5e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt @@ -6,7 +6,9 @@ import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem +import android.view.ViewGroup.MarginLayoutParams import androidx.core.graphics.Insets +import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager @@ -43,10 +45,18 @@ class SettingsActivity : super.onCreate(savedInstanceState) setContentView(ActivitySettingsBinding.inflate(layoutInflater)) supportActionBar?.setDisplayHomeAsUpEnabled(true) - - if (supportFragmentManager.findFragmentById(R.id.container) == null) { + val isMasterDetails = viewBinding.containerMaster != null + val fm = supportFragmentManager + val currentFragment = fm.findFragmentById(R.id.container) + if (currentFragment == null || (isMasterDetails && currentFragment is RootSettingsFragment)) { openDefaultFragment() } + if (isMasterDetails && fm.findFragmentById(R.id.container_master) == null) { + supportFragmentManager.commit { + setReorderingAllowed(true) + replace(R.id.container_master, RootSettingsFragment()) + } + } } override fun onTitleChanged(title: CharSequence?, color: Int) { @@ -90,7 +100,6 @@ class SettingsActivity : } } - @Suppress("DEPRECATION") override fun onPreferenceStartFragment( caller: PreferenceFragmentCompat, pref: Preference, @@ -98,32 +107,35 @@ class SettingsActivity : val fm = supportFragmentManager val fragment = fm.fragmentFactory.instantiate(classLoader, pref.fragment ?: return false) fragment.arguments = pref.extras - fragment.setTargetFragment(caller, 0) - openFragment(fragment) + openFragment(fragment, isFromRoot = caller is RootSettingsFragment) return true } override fun onWindowInsetsChanged(insets: Insets) { - viewBinding.appbar.updatePadding( - left = insets.left, - right = insets.right, - ) - viewBinding.container.updatePadding( + viewBinding.root.updatePadding( left = insets.left, right = insets.right, ) + viewBinding.cardDetails?.updateLayoutParams { + bottomMargin = marginStart + insets.bottom + } } - fun openFragment(fragment: Fragment) { + fun openFragment(fragment: Fragment, isFromRoot: Boolean) { + val hasFragment = supportFragmentManager.findFragmentById(R.id.container) != null + val isMasterDetail = viewBinding.containerMaster != null supportFragmentManager.commit { setReorderingAllowed(true) replace(R.id.container, fragment) - setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) - addToBackStack(null) + setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + if (!isMasterDetail || (hasFragment && !isFromRoot)) { + addToBackStack(null) + } } } private fun openDefaultFragment() { + val hasMaster = viewBinding.containerMaster != null val fragment = when (intent?.action) { ACTION_READER -> ReaderSettingsFragment() ACTION_SUGGESTIONS -> SuggestionsSettingsFragment() @@ -138,12 +150,12 @@ class SettingsActivity : when (intent.data?.host) { HOST_ABOUT -> AboutSettingsFragment() HOST_SYNC_SETTINGS -> SyncSettingsFragment() - else -> SettingsHeadersFragment() + else -> null } } - else -> SettingsHeadersFragment() - } + else -> null + } ?: if (hasMaster) AppearanceSettingsFragment() else RootSettingsFragment() supportFragmentManager.commit { setReorderingAllowed(true) replace(R.id.container, fragment) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsHeadersFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsHeadersFragment.kt deleted file mode 100644 index 53e1af007..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsHeadersFragment.kt +++ /dev/null @@ -1,49 +0,0 @@ -package org.koitharu.kotatsu.settings - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentTransaction -import androidx.fragment.app.commit -import androidx.preference.PreferenceFragmentCompat -import androidx.preference.PreferenceHeaderFragmentCompat -import androidx.slidingpanelayout.widget.SlidingPaneLayout -import org.koitharu.kotatsu.R - -class SettingsHeadersFragment : PreferenceHeaderFragmentCompat(), SlidingPaneLayout.PanelSlideListener { - - private var currentTitle: CharSequence? = null - - override fun onCreatePreferenceHeader(): PreferenceFragmentCompat = RootSettingsFragment() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - slidingPaneLayout.addPanelSlideListener(this) - } - - override fun onPanelSlide(panel: View, slideOffset: Float) = Unit - - override fun onPanelOpened(panel: View) { - activity?.title = currentTitle ?: getString(R.string.settings) - } - - override fun onPanelClosed(panel: View) { - activity?.setTitle(R.string.settings) - } - - fun setTitle(title: CharSequence?) { - currentTitle = title - if (slidingPaneLayout.width != 0 && slidingPaneLayout.isOpen) { - activity?.title = title - } - } - - fun openFragment(fragment: Fragment) { - childFragmentManager.commit { - setReorderingAllowed(true) - replace(androidx.preference.R.id.preferences_detail, fragment) - setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) - addToBackStack(null) - } - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt index 12b20babc..18d0f2d97 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourcesListFragment.kt @@ -26,7 +26,6 @@ import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.FragmentSettingsSourcesBinding import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.settings.SettingsActivity -import org.koitharu.kotatsu.settings.SettingsHeadersFragment import org.koitharu.kotatsu.settings.SourceSettingsFragment import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigAdapter import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigListener @@ -90,8 +89,7 @@ class SourcesListFragment : override fun onItemSettingsClick(item: SourceConfigItem.SourceItem) { val fragment = SourceSettingsFragment.newInstance(item.source) - (parentFragment as? SettingsHeadersFragment)?.openFragment(fragment) - ?: (activity as? SettingsActivity)?.openFragment(fragment) + (activity as? SettingsActivity)?.openFragment(fragment, false) } override fun onItemEnabledChanged(item: SourceConfigItem.SourceItem, isEnabled: Boolean) { diff --git a/app/src/main/res/layout-w600dp/activity_settings.xml b/app/src/main/res/layout-w600dp/activity_settings.xml index 642380efc..63aef2083 100644 --- a/app/src/main/res/layout-w600dp/activity_settings.xml +++ b/app/src/main/res/layout-w600dp/activity_settings.xml @@ -1,17 +1,17 @@ - + android:layout_height="match_parent"> + android:id="@+id/container_master" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@id/card_details" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/appbar" + app:layout_constraintWidth_max="400dp" + app:layout_constraintWidth_min="320dp" + app:layout_constraintWidth_percent="0.35" /> + + + + + + - \ No newline at end of file + diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 3b0616df6..459c2008f 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -13,8 +13,9 @@ From bc3a7fc21194ea4d83fd02f63f5c84b04c2a579c Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 5 Jun 2023 12:53:12 +0300 Subject: [PATCH 39/94] Reorganize settings --- .../kotatsu/core/ui/BasePreferenceFragment.kt | 14 +--- .../kotatsu/local/ui/ImportDialogFragment.kt | 8 +- ...agment.kt => DownloadsSettingsFragment.kt} | 71 +---------------- .../settings/NetworkSettingsFragment.kt | 79 +++++++++++++++++++ .../kotatsu/settings/RootSettingsFragment.kt | 2 +- .../settings/ServicesSettingsFragment.kt | 29 ++++++- .../kotatsu/settings/SettingsActivity.kt | 9 ++- ...ragment.kt => UserDataSettingsFragment.kt} | 39 ++++++++- .../settings/backup/BackupDialogFragment.kt | 7 +- .../settings/backup/BackupSettingsFragment.kt | 55 ------------- .../settings/backup/RestoreDialogFragment.kt | 9 ++- app/src/main/res/drawable/ic_data_privacy.xml | 12 +++ app/src/main/res/drawable/ic_services.xml | 4 +- .../res/layout-w600dp/activity_settings.xml | 26 +++++- app/src/main/res/values/strings.xml | 7 ++ app/src/main/res/xml/pref_appearance.xml | 28 ++++--- app/src/main/res/xml/pref_backup.xml | 23 ------ app/src/main/res/xml/pref_downloads.xml | 22 ++++++ .../{pref_content.xml => pref_network.xml} | 63 ++++----------- app/src/main/res/xml/pref_reader.xml | 19 +++-- app/src/main/res/xml/pref_root.xml | 31 +++++--- app/src/main/res/xml/pref_services.xml | 6 ++ .../{pref_history.xml => pref_user_data.xml} | 22 ++++++ 23 files changed, 333 insertions(+), 252 deletions(-) rename app/src/main/kotlin/org/koitharu/kotatsu/settings/{ContentSettingsFragment.kt => DownloadsSettingsFragment.kt} (56%) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/NetworkSettingsFragment.kt rename app/src/main/kotlin/org/koitharu/kotatsu/settings/{HistorySettingsFragment.kt => UserDataSettingsFragment.kt} (84%) delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupSettingsFragment.kt create mode 100644 app/src/main/res/drawable/ic_data_privacy.xml delete mode 100644 app/src/main/res/xml/pref_backup.xml create mode 100644 app/src/main/res/xml/pref_downloads.xml rename app/src/main/res/xml/{pref_content.xml => pref_network.xml} (54%) rename app/src/main/res/xml/{pref_history.xml => pref_user_data.xml} (73%) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt index ce040a63e..23fef7433 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt @@ -9,10 +9,10 @@ import androidx.core.view.updatePadding import androidx.preference.PreferenceFragmentCompat import androidx.recyclerview.widget.RecyclerView import dagger.hilt.android.AndroidEntryPoint -import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner import org.koitharu.kotatsu.core.ui.util.WindowInsetsDelegate +import org.koitharu.kotatsu.settings.SettingsActivity import javax.inject.Inject @Suppress("LeakingThis") @@ -44,9 +44,7 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : override fun onResume() { super.onResume() - if (titleId != 0) { - setTitle(getString(titleId)) - } + setTitle(if (titleId != 0) getString(titleId) else null) } @CallSuper @@ -56,11 +54,7 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : ) } - protected fun setTitle(title: CharSequence) { - activity?.let { - if (!it.resources.getBoolean(R.bool.is_tablet)) { - it.title = title - } - } + protected fun setTitle(title: CharSequence?) { + (activity as? SettingsActivity)?.setSectionTitle(title) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/ImportDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/ImportDialogFragment.kt index 6ff59f3a3..7436ccc65 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/ImportDialogFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/ImportDialogFragment.kt @@ -12,7 +12,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.AlertDialogFragment import org.koitharu.kotatsu.databinding.DialogImportBinding -import org.koitharu.kotatsu.settings.backup.BackupDialogFragment import org.koitharu.kotatsu.settings.backup.RestoreDialogFragment class ImportDialogFragment : AlertDialogFragment(), View.OnClickListener { @@ -64,9 +63,10 @@ class ImportDialogFragment : AlertDialogFragment(), View.On } private fun restoreBackup(uri: Uri?) { - RestoreDialogFragment.newInstance(uri ?: return) - .show(parentFragmentManager, BackupDialogFragment.TAG) - dismiss() + if (uri != null) { + RestoreDialogFragment.show(parentFragmentManager, uri) + dismiss() + } } companion object { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/ContentSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/DownloadsSettingsFragment.kt similarity index 56% rename from app/src/main/kotlin/org/koitharu/kotatsu/settings/ContentSettingsFragment.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/settings/DownloadsSettingsFragment.kt index 9e9091beb..151de74e5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/ContentSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/DownloadsSettingsFragment.kt @@ -3,67 +3,42 @@ package org.koitharu.kotatsu.settings import android.content.SharedPreferences import android.os.Bundle import android.view.View -import androidx.preference.ListPreference import androidx.preference.Preference -import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.cache.ContentCache -import org.koitharu.kotatsu.core.network.DoHProvider import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BasePreferenceFragment import org.koitharu.kotatsu.core.ui.dialog.StorageSelectDialog import org.koitharu.kotatsu.core.util.ext.getStorageName -import org.koitharu.kotatsu.core.util.ext.setDefaultValueCompat import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.local.data.LocalStorageManager -import org.koitharu.kotatsu.parsers.util.names import org.koitharu.kotatsu.util.ext.printStackTraceDebug import java.io.File -import java.net.Proxy import javax.inject.Inject @AndroidEntryPoint -class ContentSettingsFragment : - BasePreferenceFragment(R.string.content), +class DownloadsSettingsFragment : + BasePreferenceFragment(R.string.downloads), SharedPreferences.OnSharedPreferenceChangeListener, StorageSelectDialog.OnStorageSelectListener { @Inject lateinit var storageManager: LocalStorageManager - @Inject - lateinit var contentCache: ContentCache - @Inject lateinit var downloadsScheduler: DownloadWorker.Scheduler override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.pref_content) - findPreference(AppSettings.KEY_PREFETCH_CONTENT)?.isVisible = contentCache.isCachingEnabled - findPreference(AppSettings.KEY_DOH)?.run { - entryValues = arrayOf( - DoHProvider.NONE, - DoHProvider.GOOGLE, - DoHProvider.CLOUDFLARE, - DoHProvider.ADGUARD, - ).names() - setDefaultValueCompat(DoHProvider.NONE.name) - } + addPreferencesFromResource(R.xml.pref_downloads) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) findPreference(AppSettings.KEY_LOCAL_STORAGE)?.bindStorageName() - findPreference(AppSettings.KEY_SUGGESTIONS)?.setSummary( - if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled, - ) - bindRemoteSourcesSummary() - bindProxySummary() settings.subscribe(this) } @@ -78,29 +53,9 @@ class ContentSettingsFragment : findPreference(key)?.bindStorageName() } - AppSettings.KEY_SUGGESTIONS -> { - findPreference(AppSettings.KEY_SUGGESTIONS)?.setSummary( - if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled, - ) - } - - AppSettings.KEY_SOURCES_HIDDEN -> { - bindRemoteSourcesSummary() - } - AppSettings.KEY_DOWNLOADS_WIFI -> { updateDownloadsConstraints() } - - AppSettings.KEY_SSL_BYPASS -> { - Snackbar.make(listView, R.string.settings_apply_restart_required, Snackbar.LENGTH_INDEFINITE).show() - } - - AppSettings.KEY_PROXY_TYPE, - AppSettings.KEY_PROXY_ADDRESS, - AppSettings.KEY_PROXY_PORT -> { - bindProxySummary() - } } } @@ -131,26 +86,6 @@ class ContentSettingsFragment : } } - private fun bindRemoteSourcesSummary() { - findPreference(AppSettings.KEY_REMOTE_SOURCES)?.run { - val total = settings.remoteMangaSources.size - summary = getString(R.string.enabled_d_of_d, total - settings.hiddenSources.size, total) - } - } - - private fun bindProxySummary() { - findPreference(AppSettings.KEY_PROXY)?.run { - val type = settings.proxyType - val address = settings.proxyAddress - val port = settings.proxyPort - summary = if (type == Proxy.Type.DIRECT || address.isNullOrEmpty() || port == 0) { - context.getString(R.string.disabled) - } else { - "$address:$port" - } - } - } - private fun updateDownloadsConstraints() { val preference = findPreference(AppSettings.KEY_DOWNLOADS_WIFI) viewLifecycleScope.launch { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/NetworkSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/NetworkSettingsFragment.kt new file mode 100644 index 000000000..48d6f6407 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/NetworkSettingsFragment.kt @@ -0,0 +1,79 @@ +package org.koitharu.kotatsu.settings + +import android.content.SharedPreferences +import android.os.Bundle +import android.view.View +import androidx.preference.ListPreference +import androidx.preference.Preference +import com.google.android.material.snackbar.Snackbar +import dagger.hilt.android.AndroidEntryPoint +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.cache.ContentCache +import org.koitharu.kotatsu.core.network.DoHProvider +import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.core.ui.BasePreferenceFragment +import org.koitharu.kotatsu.core.util.ext.setDefaultValueCompat +import org.koitharu.kotatsu.parsers.util.names +import java.net.Proxy +import javax.inject.Inject + +@AndroidEntryPoint +class NetworkSettingsFragment : + BasePreferenceFragment(R.string.network), + SharedPreferences.OnSharedPreferenceChangeListener { + + @Inject + lateinit var contentCache: ContentCache + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.pref_network) + findPreference(AppSettings.KEY_PREFETCH_CONTENT)?.isVisible = contentCache.isCachingEnabled + findPreference(AppSettings.KEY_DOH)?.run { + entryValues = arrayOf( + DoHProvider.NONE, + DoHProvider.GOOGLE, + DoHProvider.CLOUDFLARE, + DoHProvider.ADGUARD, + ).names() + setDefaultValueCompat(DoHProvider.NONE.name) + } + bindProxySummary() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + settings.subscribe(this) + } + + override fun onDestroyView() { + settings.unsubscribe(this) + super.onDestroyView() + } + + override fun onSharedPreferenceChanged(prefs: SharedPreferences?, key: String?) { + when (key) { + AppSettings.KEY_SSL_BYPASS -> { + Snackbar.make(listView, R.string.settings_apply_restart_required, Snackbar.LENGTH_INDEFINITE).show() + } + + AppSettings.KEY_PROXY_TYPE, + AppSettings.KEY_PROXY_ADDRESS, + AppSettings.KEY_PROXY_PORT -> { + bindProxySummary() + } + } + } + + private fun bindProxySummary() { + findPreference(AppSettings.KEY_PROXY)?.run { + val type = settings.proxyType + val address = settings.proxyAddress + val port = settings.proxyPort + summary = if (type == Proxy.Type.DIRECT || address.isNullOrEmpty() || port == 0) { + context.getString(R.string.disabled) + } else { + "$address:$port" + } + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/RootSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/RootSettingsFragment.kt index 7d737ee50..e3c64b76e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/RootSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/RootSettingsFragment.kt @@ -4,7 +4,7 @@ import android.os.Bundle import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BasePreferenceFragment -class RootSettingsFragment : BasePreferenceFragment(R.string.settings) { +class RootSettingsFragment : BasePreferenceFragment(0) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_root) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/ServicesSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/ServicesSettingsFragment.kt index 04bbd96ad..7e1409c9d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/ServicesSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/ServicesSettingsFragment.kt @@ -3,8 +3,10 @@ package org.koitharu.kotatsu.settings import android.accounts.AccountManager import android.content.ActivityNotFoundException import android.content.Intent +import android.content.SharedPreferences import android.net.Uri import android.os.Bundle +import android.view.View import androidx.preference.Preference import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint @@ -27,7 +29,8 @@ import org.koitharu.kotatsu.util.ext.printStackTraceDebug import javax.inject.Inject @AndroidEntryPoint -class ServicesSettingsFragment : BasePreferenceFragment(R.string.services) { +class ServicesSettingsFragment : BasePreferenceFragment(R.string.services), + SharedPreferences.OnSharedPreferenceChangeListener { @Inject lateinit var shikimoriRepository: ShikimoriRepository @@ -43,6 +46,17 @@ class ServicesSettingsFragment : BasePreferenceFragment(R.string.services) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_services) + bindSuggestionsSummary() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + settings.subscribe(this) + } + + override fun onDestroyView() { + settings.unsubscribe(this) + super.onDestroyView() } override fun onResume() { @@ -53,6 +67,13 @@ class ServicesSettingsFragment : BasePreferenceFragment(R.string.services) { bindSyncSummary() } + override fun onSharedPreferenceChanged(prefs: SharedPreferences?, key: String?) { + when (key) { + AppSettings.KEY_SUGGESTIONS -> bindSuggestionsSummary() + } + } + + override fun onPreferenceTreeClick(preference: Preference): Boolean { return when (preference.key) { AppSettings.KEY_SHIKIMORI -> { @@ -156,4 +177,10 @@ class ServicesSettingsFragment : BasePreferenceFragment(R.string.services) { findPreference(AppSettings.KEY_SYNC_SETTINGS)?.isEnabled = account != null } } + + private fun bindSuggestionsSummary() { + findPreference(AppSettings.KEY_SUGGESTIONS)?.setSummary( + if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled, + ) + } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt index 366cd8c5e..ce3731f83 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt @@ -24,6 +24,7 @@ import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat import org.koitharu.kotatsu.core.util.ext.isScrolledToTop +import org.koitharu.kotatsu.core.util.ext.textAndVisible import org.koitharu.kotatsu.databinding.ActivitySettingsBinding import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.parsers.model.MangaSource @@ -121,6 +122,12 @@ class SettingsActivity : } } + fun setSectionTitle(title: CharSequence?) { + viewBinding.textViewHeader?.apply { + textAndVisible = title + } ?: setTitle(title ?: getString(R.string.settings)) + } + fun openFragment(fragment: Fragment, isFromRoot: Boolean) { val hasFragment = supportFragmentManager.findFragmentById(R.id.container) != null val isMasterDetail = viewBinding.containerMaster != null @@ -139,7 +146,7 @@ class SettingsActivity : val fragment = when (intent?.action) { ACTION_READER -> ReaderSettingsFragment() ACTION_SUGGESTIONS -> SuggestionsSettingsFragment() - ACTION_HISTORY -> HistorySettingsFragment() + ACTION_HISTORY -> UserDataSettingsFragment() ACTION_TRACKER -> TrackerSettingsFragment() ACTION_SOURCE -> SourceSettingsFragment.newInstance( intent.getSerializableExtraCompat(EXTRA_SOURCE) as? MangaSource ?: MangaSource.LOCAL, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/UserDataSettingsFragment.kt similarity index 84% rename from app/src/main/kotlin/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/settings/UserDataSettingsFragment.kt index 34b2fdb37..c21c4571d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/UserDataSettingsFragment.kt @@ -1,7 +1,11 @@ package org.koitharu.kotatsu.settings +import android.content.ActivityNotFoundException +import android.net.Uri import android.os.Bundle import android.view.View +import androidx.activity.result.ActivityResultCallback +import androidx.activity.result.contract.ActivityResultContracts import androidx.lifecycle.Lifecycle import androidx.preference.Preference import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -24,11 +28,14 @@ import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope import org.koitharu.kotatsu.local.data.CacheDir import org.koitharu.kotatsu.local.data.LocalStorageManager import org.koitharu.kotatsu.search.domain.MangaSearchRepository +import org.koitharu.kotatsu.settings.backup.BackupDialogFragment +import org.koitharu.kotatsu.settings.backup.RestoreDialogFragment import org.koitharu.kotatsu.tracker.domain.TrackingRepository +import org.koitharu.kotatsu.util.ext.printStackTraceDebug import javax.inject.Inject @AndroidEntryPoint -class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cache) { +class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privacy), ActivityResultCallback { @Inject lateinit var trackerRepo: TrackingRepository @@ -48,8 +55,13 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach @Inject lateinit var shortcutsUpdater: ShortcutsUpdater + private val backupSelectCall = registerForActivityResult( + ActivityResultContracts.OpenDocument(), + this, + ) + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.pref_history) + addPreferencesFromResource(R.xml.pref_user_data) findPreference(AppSettings.KEY_SHORTCUTS)?.isVisible = shortcutsUpdater.isDynamicShortcutsAvailable() } @@ -116,10 +128,33 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach true } + AppSettings.KEY_BACKUP -> { + BackupDialogFragment.show(childFragmentManager) + true + } + + AppSettings.KEY_RESTORE -> { + try { + backupSelectCall.launch(arrayOf("*/*")) + } catch (e: ActivityNotFoundException) { + e.printStackTraceDebug() + Snackbar.make( + listView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT, + ).show() + } + true + } + else -> super.onPreferenceTreeClick(preference) } } + override fun onActivityResult(result: Uri?) { + if (result != null) { + RestoreDialogFragment.show(childFragmentManager, result) + } + } + private fun clearCache(preference: Preference, cache: CacheDir) { val ctx = preference.context.applicationContext viewLifecycleScope.launch { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt index 1a93c12d9..caf25f180 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt @@ -7,6 +7,7 @@ import android.view.ViewGroup import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.core.view.isVisible +import androidx.fragment.app.FragmentManager import androidx.fragment.app.viewModels import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint @@ -101,6 +102,10 @@ class BackupDialogFragment : AlertDialogFragment() { companion object { - const val TAG = "BackupDialogFragment" + private const val TAG = "BackupDialogFragment" + + fun show(fm: FragmentManager) { + BackupDialogFragment().show(fm, TAG) + } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupSettingsFragment.kt deleted file mode 100644 index fbeb28594..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupSettingsFragment.kt +++ /dev/null @@ -1,55 +0,0 @@ -package org.koitharu.kotatsu.settings.backup - -import android.content.ActivityNotFoundException -import android.net.Uri -import android.os.Bundle -import androidx.activity.result.ActivityResultCallback -import androidx.activity.result.contract.ActivityResultContracts -import androidx.preference.Preference -import com.google.android.material.snackbar.Snackbar -import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.core.ui.BasePreferenceFragment -import org.koitharu.kotatsu.util.ext.printStackTraceDebug - -class BackupSettingsFragment : - BasePreferenceFragment(R.string.backup_restore), - ActivityResultCallback { - - private val backupSelectCall = registerForActivityResult( - ActivityResultContracts.OpenDocument(), - this, - ) - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.pref_backup) - } - - override fun onPreferenceTreeClick(preference: Preference): Boolean { - return when (preference.key) { - AppSettings.KEY_BACKUP -> { - BackupDialogFragment().show(childFragmentManager, BackupDialogFragment.TAG) - true - } - - AppSettings.KEY_RESTORE -> { - try { - backupSelectCall.launch(arrayOf("*/*")) - } catch (e: ActivityNotFoundException) { - e.printStackTraceDebug() - Snackbar.make( - listView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT, - ).show() - } - true - } - - else -> super.onPreferenceTreeClick(preference) - } - } - - override fun onActivityResult(result: Uri?) { - RestoreDialogFragment.newInstance(result ?: return) - .show(childFragmentManager, BackupDialogFragment.TAG) - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt index f2d0b200e..c697a63fa 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt @@ -5,6 +5,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup import androidx.core.view.isVisible +import androidx.fragment.app.FragmentManager import androidx.fragment.app.viewModels import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint @@ -87,10 +88,12 @@ class RestoreDialogFragment : AlertDialogFragment() { companion object { const val ARG_FILE = "file" - const val TAG = "RestoreDialogFragment" + private const val TAG = "RestoreDialogFragment" - fun newInstance(uri: Uri) = RestoreDialogFragment().withArgs(1) { - putString(ARG_FILE, uri.toString()) + fun show(fm: FragmentManager, uri: Uri) { + RestoreDialogFragment().withArgs(1) { + putString(ARG_FILE, uri.toString()) + }.show(fm, TAG) } } } diff --git a/app/src/main/res/drawable/ic_data_privacy.xml b/app/src/main/res/drawable/ic_data_privacy.xml new file mode 100644 index 000000000..0697d42ee --- /dev/null +++ b/app/src/main/res/drawable/ic_data_privacy.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_services.xml b/app/src/main/res/drawable/ic_services.xml index fe6404dbc..593c9666c 100644 --- a/app/src/main/res/drawable/ic_services.xml +++ b/app/src/main/res/drawable/ic_services.xml @@ -2,10 +2,10 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" - android:tint="?attr/colorControlNormal" + android:tint="?colorControlNormal" android:viewportWidth="24" android:viewportHeight="24"> + android:pathData="M22,13.5C22,15.26 20.7,16.72 19,16.96V20A2,2 0 0,1 17,22H13.2V21.7A2.7,2.7 0 0,0 10.5,19C9,19 7.8,20.21 7.8,21.7V22H4A2,2 0 0,1 2,20V16.2H2.3C3.79,16.2 5,15 5,13.5C5,12 3.79,10.8 2.3,10.8H2V7A2,2 0 0,1 4,5H7.04C7.28,3.3 8.74,2 10.5,2C12.26,2 13.72,3.3 13.96,5H17A2,2 0 0,1 19,7V10.04C20.7,10.28 22,11.74 22,13.5M17,15H18.5A1.5,1.5 0 0,0 20,13.5A1.5,1.5 0 0,0 18.5,12H17V7H12V5.5A1.5,1.5 0 0,0 10.5,4A1.5,1.5 0 0,0 9,5.5V7H4V9.12C5.76,9.8 7,11.5 7,13.5C7,15.5 5.75,17.2 4,17.88V20H6.12C6.8,18.25 8.5,17 10.5,17C12.5,17 14.2,18.25 14.88,20H17V15Z" /> diff --git a/app/src/main/res/layout-w600dp/activity_settings.xml b/app/src/main/res/layout-w600dp/activity_settings.xml index 63aef2083..bbbd8dadf 100644 --- a/app/src/main/res/layout-w600dp/activity_settings.xml +++ b/app/src/main/res/layout-w600dp/activity_settings.xml @@ -2,6 +2,7 @@ @@ -50,10 +51,29 @@ app:layout_constraintStart_toEndOf="@id/container_master" app:layout_constraintTop_toBottomOf="@id/appbar"> - + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5dad409f3..bd61d47ac 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -433,4 +433,11 @@ Password Authorization (optional) Invalid port number + Network + Data and privacy + Restore previously created backup + Allow zoom in gesture in webtoon mode + Show the current time and reading progress at the top of the screen + Show page numbers in bottom corner + Animate page switching diff --git a/app/src/main/res/xml/pref_appearance.xml b/app/src/main/res/xml/pref_appearance.xml index 5f2058cee..ead9e176a 100644 --- a/app/src/main/res/xml/pref_appearance.xml +++ b/app/src/main/res/xml/pref_appearance.xml @@ -3,6 +3,11 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> + + - - + + + + + + - - + android:title="@string/exit_confirmation" /> diff --git a/app/src/main/res/xml/pref_backup.xml b/app/src/main/res/xml/pref_backup.xml deleted file mode 100644 index 7fc94bcba..000000000 --- a/app/src/main/res/xml/pref_backup.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/xml/pref_downloads.xml b/app/src/main/res/xml/pref_downloads.xml new file mode 100644 index 000000000..82554d8b9 --- /dev/null +++ b/app/src/main/res/xml/pref_downloads.xml @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/app/src/main/res/xml/pref_content.xml b/app/src/main/res/xml/pref_network.xml similarity index 54% rename from app/src/main/res/xml/pref_content.xml rename to app/src/main/res/xml/pref_network.xml index ccf022e00..2d3bd6e38 100644 --- a/app/src/main/res/xml/pref_content.xml +++ b/app/src/main/res/xml/pref_network.xml @@ -4,22 +4,6 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> - - - - - - + + + + - - - - - - - - - - - - - + diff --git a/app/src/main/res/xml/pref_reader.xml b/app/src/main/res/xml/pref_reader.xml index 525a46202..a078e2928 100644 --- a/app/src/main/res/xml/pref_reader.xml +++ b/app/src/main/res/xml/pref_reader.xml @@ -19,8 +19,15 @@ android:entries="@array/zoom_modes" android:key="zoom_mode" android:title="@string/scale_mode" + app:allowDividerAbove="true" app:useSimpleSummaryProvider="true" /> + + - - + android:summary="@string/reader_info_bar_summary" + android:title="@string/reader_info_bar" + app:allowDividerAbove="true" /> - - + android:title="@string/remote_sources" /> + android:fragment="org.koitharu.kotatsu.settings.NetworkSettingsFragment" + android:icon="@drawable/ic_web" + android:title="@string/network" /> + + + + + android:fragment="org.koitharu.kotatsu.settings.ServicesSettingsFragment" + android:icon="@drawable/ic_services" + android:title="@string/services" /> + + + + + + + + + + + + Date: Mon, 5 Jun 2023 11:53:35 +0200 Subject: [PATCH 40/94] Translated using Weblate (Belarusian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (421 of 421 strings) Translated using Weblate (Belarusian) Currently translated at 100.0% (416 of 416 strings) Co-authored-by: Макар Разин Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/ Translation: Kotatsu/Strings --- app/src/main/res/values-be/strings.xml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index 33e0b519d..8c17722f5 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -45,7 +45,7 @@ Тэма Светлая Цёмная - Аўтаматычна + Як у сістэме Старонкi Ачысціць Вы ўпэўненыя, што жадаеце ачысціць гісторыю\? @@ -136,8 +136,8 @@ Падагнаць па вышыні Падагнаць па шырыні Зыходны памер - Чорная цёмная тэма - Карысна для AMOLED экранаў + Чорная + Спажывае менш энергіі на экранах AMOLED Рэзервовае капіяванне і аднаўленне Стварыць рэзервовую копію Аднавіць данныя @@ -412,4 +412,9 @@ Спампоўкі былі адменены Пераклады WebView недаступны: праверце, ці ўсталяваны пастаўшчык WebView + Тып + Адрас + Порт + Проксі + Ачысціць сеткавы кэш \ No newline at end of file From cd8381cbfb8867d097649882f69f860c87b7b23b Mon Sep 17 00:00:00 2001 From: "J. Lavoie" Date: Mon, 5 Jun 2023 11:53:36 +0200 Subject: [PATCH 41/94] Translated using Weblate (French) Currently translated at 100.0% (416 of 416 strings) Co-authored-by: J. Lavoie Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/ Translation: Kotatsu/Strings --- app/src/main/res/values-fr/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index ef3ad9f8a..758eedf94 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -410,4 +410,6 @@ Les téléchargements ont été supprimés Les téléchargements ont été annulés Voulez-vous recevoir des suggestions de mangas personnalisées \? + WebView non disponible : vérifier si le fournisseur WebView est installé + Traductions \ No newline at end of file From ae5cebd42df20b215839ef40498e6455a5c82dce Mon Sep 17 00:00:00 2001 From: kuragehime Date: Mon, 5 Jun 2023 11:53:36 +0200 Subject: [PATCH 42/94] Translated using Weblate (Japanese) Currently translated at 100.0% (431 of 431 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (430 of 430 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (427 of 427 strings) Translated using Weblate (Japanese) Currently translated at 91.8% (382 of 416 strings) Co-authored-by: kuragehime Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ja/ Translation: Kotatsu/Strings --- app/src/main/res/values-ja/strings.xml | 802 +++++++++++++------------ 1 file changed, 427 insertions(+), 375 deletions(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 8b9bc139c..65274a235 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1,378 +1,430 @@ - 履歴 - ロード中… - チャプター %1$d of %2$d - 共有 - 履歴を削除 - 検索 - 漫画を検索 - 閉じる - お気に入り - エラーが発生しました - 詳細 - - リスト - 詳細リスト - グリッド - リストモード - リモートソース - 再試行 - 何も見つかりませんでした - まだ履歴はありません - 読む - お気に入りの本はありません - お気に入りの本 - 新たなカテゴリー - 追加 - 保存 - ショートカットを作成します… - 共有する%s - ダウンロード中… - 処理中… - ダウンロードした本 - ダウンロード - 名前 - 人気 - ローカルストレージ - 最新 - 評価 - ソート順に並べ替え - フォローシステム - クリア - すべての履歴を永久にクリアしますか? - 削除 - 「%s 」がローカルストレージから削除されました - ページを保存 - 保存しました - 画像を共有する - インポート - 消去 - この操作はサポートされていません - 説明がありません - 履歴とキャッシュ - ページのキャッシュをクリアする - B|kB|MB|GB|TB - 設定 - ライトテーマ - フィルター - ダークテーマ - ページ - テーマ - ネットワークエラー - アップデート - ZIPファイルまたはCBZファイルを選択してください。 - 標準 - ウェブトゥーン - 読み取りモード - グリッドのサイズ - %sで検索 - 漫画を削除 - お使いのデバイスから「%s」を完全に削除しますか? - リーダーの設定 - ページを変更 - エッジタップ - ボリュームボタン - 続ける - エラー - サムネイルキャッシュをクリア - クリア - ジェスチャーのみ - 内部ストレージ - ドメイン - ブラウザーで開く - この漫画には%sがあります。 すべて保存しますか? - 保存 - 通知 - %2$dの%1$d - 新しいチャプター - ダウンロード - 通知の設定 - 通知音 - LEDインジケータ - バイブレーション - お気に入りのカテゴリー - 削除 - クエリを再定式化してみてください。 - 読んだ内容がここに表示されます - サイドメニューで何を読むかを見つけてください。 - 最初に何かを保存する - 本棚 - 最近 - ページアニメーション - ダウンロード用のフォルダ - 利用出来ません - 使用可能なストレージがありません - その他のストレージ - 完了 - 全てのお気に入り - 後で読む - 更新 - あなたが読んでいるものの新しいチャプターがここに示されています - の検索結果 - サイズ:%s - 更新フィードをクリア - クリア - アップデート - フィードの更新はまもなく開始されます - アップデートを確認 - チェックしない - Kotatsuを起動したときにパスワードを入力する - パスワードを繰り返す - パスワードが違います - この本の詳細 - 現在のバージョン%s - 検索履歴をクリア - 外部ストレージ - Kotatsuの新しい更新が利用可能です - ここは空っぽです… - 空のカテゴリー - オンラインソースから保存するかファイルをインポートします。 - 新しいバージョン:%s - 画面を回転させる - パスワードを入力してください - パスワードが間違っています - アプリを保護する - 最新のアップデートを確認する - 利用可能なアップデートはありません - 右から左 - 承認済み - %sへのログインはサポートされていません - 完成 - 進行中 - デフォルト - ナンバリングページ - 使用したソース - 利用可能なソース - 新しいカテゴリー - 高さを合わせる - チャプターがありません - すべての更新履歴を完全に消去しますか? - この不足した章をダウンロードしたり、オンラインで読んだりすることができます。 - このコンテンツを表示するにはサインインしてください - ファイルが見つかりません - パスワードは4文字以上である必要があります - ちょうど今 - ずっと前 - バックアップを保存 - グループ - フィードをクリア - バックアップから復元 - 確認 - 履歴とお気に入りのバックアップを作成して復元できます - 続きを読む - ブラック - データは復元されましたがエラーが発生しました - 最近の検索クエリを全て完全に削除しますか? - 幅を合わせる - 新しいチャプターを探しています - アプリを起動するためのパスワードを入力してください - データバックアップを作成 - 解決しました - タップして再試行してください - CAPTCHAが必要です - デフォルト:%s - 昨日 - このアプリを翻訳 - 全てのデータが復元されました - 復元 - 準備中… - 開始時に維持 - バックアップと復元 - リバース - 選択した構成はこの漫画のために記憶されます - クッキーを削除 - フィットセンター - 全てのソースからログアウトされます - NSFW漫画を履歴から除外する - キュー - 全てのCookieが削除されました - 一部のデバイスはシステムでの動作が異なり、バックグラウンドタスクが中断される可能性があります。 - ジャンル - スケールモード - 今日 - Kotatsuを翻訳する(Weblateのサイトに移動します) - 次のページ - サイレント - サインイン - ようこそ - AMOLEDスクリーンでさらに少ない電力を使用 - コンピューティング… - 許可する - 常にブロック - スクリーンショットポリシー - NSFWでブロック - 提案 - すべてのデータは、このデバイス上でローカルに分析されます。お客様のデータが他のサービスに転送されることはありません - サジェスト機能を有効 - あなたの好みに合わせて漫画を提案 - ジャンルリストを読み込めません - 無効 - マンガを読み始めると、個人的な提案を受けることができます - 有効 - NSFWのマンガを提案しない - フィルターをリセット - ジャンルを探す - Wi-Fiのみ使用 - 決して - 漫画を読みたい言語を選択します。後で設定から変更することができます。 - 常に - ページのプリロード - %sとしてログイン - 18歳以上 - さまざまな言語 - チャプターを検索 - この漫画の章はありません - %1$s%% - コンテンツ - 更新のご提案 - 外観 - ジャンルを除く - サジェストで表示したくないジャンルを指定 - 選択した項目をデバイスから完全に削除しますか? - 削除が完了しました - IPアドレスのブロックを回避することができます - 保存されたマンガの処理 - ダウンロードの速度低下 - チャプターはバックグラウンドで削除されます。時間がかかる場合があります - 隠す - 新しいマンガソースが利用可能です - 新着チャプターの確認とお知らせ - 読んでいるマンガの更新情報をお知らせします - 通知を有効にする - 通知はありませんが、新しいチャプターはリストでハイライト表示されます - 名称 - 編集 - カテゴリーを編集する - お気に入りのカテゴリーはありません - ブックマーク - ブックマーク削除 - 元に戻す - 履歴から削除 - ブックマークの追加 - ブックマークの削除 - ブックマークを追加 - HTTPS 経由の DNS - リーダーモードの自動検出 - デフォルトモード - マンガがウェブトゥーンかどうかを自動判定 - バッテリー最適化の無効化 - バックグラウンドの更新チェックを支援 - 何か問題が発生しました。開発者にバグレポートを提出し、解決にご協力ください。 - 送信 - すべて無効にする - 最近読んだ漫画 - 指紋がある場合は、指紋を使用する - お気に入りの漫画 - 報告 - 読書 - 再読込 - 完了 - 保留中 - 追跡 - ログアウト - 予定 - ドロップ - データの削除 - 履歴とお気に入りに既読率を表示する - いくつかの問題の場合に助けることができる。すべての認証が無効になります - 読書の進行状況インジケーターを表示 - NSFWとマークされたマンガは履歴に追加されず、進行状況も保存されない - すべて表示 - 無効なドメイン - 範囲を選択 - コンテンツが見つからない、または削除された - 管理 - ランダム - 選択したお気に入りカテゴリを本当に削除してもよいですか? + 履歴 + ロード中… + チャプター %1$d of %2$d + 共有 + 履歴を削除 + 検索 + 漫画を検索 + 閉じる + お気に入り + エラーが発生しました + 詳細 + + リスト + 詳細リスト + グリッド + リストモード + マンガのソース + 再試行 + 何も見つかりませんでした + まだ履歴はありません + 読む + お気に入りの本はありません + お気に入りの本 + 新たなカテゴリー + 追加 + 保存 + ショートカットを作成します… + 共有する%s + ダウンロード中… + 処理中… + ダウンロードした本 + ダウンロード + 名前 + 人気 + ローカルストレージ + 最新 + 評価 + ソート順に並べ替え + フォローシステム + クリア + すべての履歴を永久にクリアしますか? + 削除 + 「%s 」がローカルストレージから削除されました + ページを保存 + 保存しました + 画像を共有する + インポート + 消去 + この操作はサポートされていません + 説明がありません + 履歴とキャッシュ + ページのキャッシュをクリアする + B|kB|MB|GB|TB + 設定 + ライトテーマ + フィルター + ダークテーマ + ページ + テーマ + ネットワークエラー + アップデート + ZIPファイルまたはCBZファイルを選択してください。 + 標準 + ウェブトゥーン + 読み取りモード + グリッドのサイズ + %sで検索 + 漫画を削除 + お使いのデバイスから「%s」を完全に削除しますか? + リーダーの設定 + ページを変更 + エッジタップ + ボリュームボタン + 続ける + エラー + サムネイルキャッシュをクリア + クリア + ジェスチャーのみ + 内部ストレージ + ドメイン + ブラウザーで開く + この漫画には%sがあります。 すべて保存しますか? + 保存 + 通知 + %2$dの%1$d + 新しいチャプター + ダウンロード + 通知の設定 + 通知音 + LEDインジケータ + バイブレーション + お気に入りのカテゴリー + 削除 + クエリを再定式化してみてください。 + 読んだ内容がここに表示されます + サイドメニューで何を読むかを見つけてください。 + 最初に何かを保存する + 本棚 + 最近 + ページアニメーション + ダウンロード用のフォルダ + 利用出来ません + 使用可能なストレージがありません + その他のストレージ + 完了 + 全てのお気に入り + 後で読む + 更新 + あなたが読んでいるものの新しいチャプターがここに示されています + の検索結果 + サイズ:%s + 更新フィードをクリア + クリア + アップデート + フィードの更新はまもなく開始されます + アップデートを確認 + チェックしない + Kotatsuを起動したときにパスワードを入力する + パスワードを繰り返す + パスワードが違います + この本の詳細 + 現在のバージョン%s + 検索履歴をクリア + 外部ストレージ + Kotatsuの新しい更新が利用可能です + ここは空っぽです… + 空のカテゴリー + オンラインソースから保存するかファイルをインポートします。 + 新しいバージョン:%s + 画面を回転させる + パスワードを入力してください + パスワードが間違っています + アプリを保護する + 最新のアップデートを確認する + 利用可能なアップデートはありません + 右から左 + 承認済み + %sへのログインはサポートされていません + 完成 + 進行中 + デフォルト + ナンバリングページ + 使用したソース + 利用可能なソース + 新しいカテゴリー + 高さを合わせる + チャプターがありません + すべての更新履歴を完全に消去しますか? + この不足した章をダウンロードしたり、オンラインで読んだりすることができます。 + このコンテンツを表示するにはサインインしてください + ファイルが見つかりません + パスワードは4文字以上である必要があります + ちょうど今 + ずっと前 + バックアップを保存 + グループ + フィードをクリア + バックアップから復元 + 確認 + 履歴とお気に入りのバックアップを作成して復元できます + 続きを読む + ブラック + データは復元されましたがエラーが発生しました + 最近の検索クエリを全て完全に削除しますか? + 幅を合わせる + 新しいチャプターを探しています + アプリを起動するためのパスワードを入力してください + データバックアップを作成 + 解決しました + タップして再試行してください + CAPTCHAが必要です + デフォルト:%s + 昨日 + このアプリを翻訳 + 全てのデータが復元されました + 復元 + 準備中… + 開始時に維持 + バックアップと復元 + リバース + 選択した構成はこの漫画のために記憶されます + クッキーを削除 + フィットセンター + 全てのソースからログアウトされます + NSFW漫画を履歴から除外する + キュー + 全てのCookieが削除されました + 一部のデバイスはシステムでの動作が異なり、バックグラウンドタスクが中断される可能性があります。 + ジャンル + スケールモード + 今日 + Kotatsuを翻訳する(Weblateのサイトに移動します) + 次のページ + サイレント + サインイン + ようこそ + AMOLEDスクリーンでさらに少ない電力を使用 + コンピューティング… + 許可する + 常にブロック + スクリーンショットポリシー + NSFWでブロック + 提案 + すべてのデータは、このデバイス上でローカルでのみ分析され、どこにも送信されることはありません。 + サジェスト機能を有効 + あなたの好みに合わせて漫画を提案 + ジャンルリストを読み込めません + 無効 + マンガを読み始めると、個人的な提案を受けることができます + 有効 + NSFWのマンガを提案しない + フィルターをリセット + ジャンルを探す + Wi-Fiのみ使用 + 決して + 漫画を読みたい言語を選択します。後で設定から変更することができます。 + 常に + ページのプリロード + %sとしてログイン + 18歳以上 + さまざまな言語 + チャプターを検索 + この漫画の章はありません + %1$s%% + コンテンツ + 更新のご提案 + 外観 + ジャンルを除く + サジェストで表示したくないジャンルを指定 + 選択した項目をデバイスから完全に削除しますか? + 削除が完了しました + IPアドレスのブロックを回避することができます + 保存されたマンガの処理 + ダウンロードの速度低下 + チャプターはバックグラウンドで削除されます + 隠す + 新しいマンガソースが利用可能です + 新着チャプターの確認とお知らせ + 読んでいるマンガの更新情報をお知らせします + 通知を有効にする + 通知はありませんが、新しいチャプターはリストでハイライト表示されます + 名称 + 編集 + カテゴリーを編集する + お気に入りのカテゴリーはありません + ブックマーク + ブックマーク削除 + 元に戻す + 履歴から削除 + ブックマークの追加 + ブックマークの削除 + ブックマークを追加 + HTTPS 経由の DNS + リーダーモードの自動検出 + デフォルトモード + マンガがウェブトゥーンかどうかを自動判定 + バッテリー最適化の無効化 + バックグラウンドの更新チェックを支援 + 何か問題が発生しました。開発者にバグレポートを提出し、解決にご協力ください。 + 送信 + すべて無効にする + 最近読んだ漫画 + 指紋がある場合は、指紋を使用する + お気に入りの漫画 + 報告 + 読書 + 再読込 + 完了 + 保留中 + 追跡 + ログアウト + 予定 + ドロップ + データの削除 + 履歴とお気に入りに既読率を表示する + いくつかの問題の場合に助けることができる。すべての認証が無効になります + 読書の進行状況インジケーターを表示 + NSFWとマークされたマンガは履歴に追加されず、進行状況も保存されない + すべて表示 + 無効なドメイン + 範囲を選択 + コンテンツが見つからない、または削除された + 管理 + ランダム + 選択したお気に入りカテゴリを本当に削除してもよいですか? \nその中にあるマンガはすべて失われ、元に戻すことはできません。 - - 探検 - アプリを終了するには、戻るを2回押してください - 保存したマンガ - チャプターなし - 自動スクロール - マンガのインポート - 続行するにはメールアドレスを入力してください - «探索»セクションで読むべきものを見つける - インポートが完了しました - あなたのマンガはここに表示されます - キャンセル - データの同期 - アカウントは既に存在します - 戻る - 過去 2 時間 - ブックマークはまだありません - 同期 - ページキャッシュ - 利用可能 - すべての履歴を消去する - 履歴が消去されました - 並べ替え - マンガを読みながらブックマークを作成することができます - ブックマークを削除しました - マンガのソースがない - マンガのソースを有効にして、オンラインでマンガを読めるようにする - もう一度戻るを押して終了します - %s -%s - 退出確認 - ストレージの使用状況 - その他のキャッシュ - シークレットモード - 画像を含むフォルダ - まもなくインポートが開始されます - お気に入りから削除 - オプション - ストレージから元のファイルを削除して、容量を節約することができます - Ch.%1$d/%2$d Pg.%3$d/%4$d - リーダーで情報バーを表示する - コミックアーカイブ - フィード - エラーの詳細:<br><tt>%1$s</tt><br><br>1. <a href=%2$s>Webブラウザで漫画を開いてみて</a>、そのソースで利用できるか確認する<br>2. 利用できる場合は、開発者にエラーレポートを送信する</a>。 - 人間工学に基づいたリーダーコントロール - 最近のマンガのショートカットを表示 - アプリケーションアイコンを長押しして最近のマンガを利用できるようにする - 右端をタップするか、右キーを押すと、常に次のページに切り替わります - 色補正 - 輝度 - コントラスト - リセット - 未保存の変更を保存または破棄しますか\? - 選択した色の設定は、この漫画のために記憶されます - 破棄 - デバイスに空き容量がありません - ページ切り替えスライダーを表示 - サーバーサイドエラー (%1$d) です。後で再試行してください - 新しいチャプターの情報も明確に - さまざまな言語 - ネットワークが利用できません - Wi-Fiまたはモバイルネットワークをオンにして、オンラインでマンガを読むことができます - Webtoonズーム - コンパクト - マミミ - - ここには何もありません - 読書の進捗状況を確認するには、マンガの詳細画面で「メニュー」→「追跡」を選択します。 - サービス - デバッグ目的でいくつかのアクションを記録する - ミク - ユーザー エージェント ヘッダー - コンテンツのプリロード - ログを共有 - 不安定な更新を許可 - アプリのベータ版へのアップデートを提案する - ダウンロードが開始されました - 言語 - ソースが無効になっています - 現在としてマーク - ログ記録を有効にする - 疑わしいコンテンツを表示する - ダイナミック - 配色 - グリッドビューで表示 - アスカ - ミオン - リッカ - さくら - この変更を適用するには、アプリケーションを再起動してください - + + 探検 + アプリを終了するには、戻るを2回押してください + 保存したマンガ + チャプターなし + 自動スクロール + マンガのインポート + 続行するにはメールアドレスを入力してください + «探索»セクションで読むべきものを見つける + インポートが完了しました + あなたのマンガはここに表示されます + キャンセル + データの同期 + アカウントは既に存在します + 戻る + 過去 2 時間 + ブックマークはまだありません + 同期 + ページキャッシュ + 利用可能 + すべての履歴を消去する + 履歴が消去されました + 並べ替え + マンガを読みながらブックマークを作成することができます + ブックマークを削除しました + マンガのソースがない + マンガのソースを有効にして、オンラインでマンガを読めるようにする + もう一度戻るを押して終了します + %s -%s + 退出確認 + ストレージの使用状況 + その他のキャッシュ + シークレットモード + 画像を含むフォルダ + まもなくインポートが開始されます + お気に入りから削除 + オプション + ストレージから元のファイルを削除して、容量を節約することができます + Ch.%1$d/%2$d Pg.%3$d/%4$d + リーダーで情報バーを表示する + コミックアーカイブ + フィード + エラーの詳細:<br><tt>%1$s</tt><br><br>1. <a href=%2$s>Webブラウザで漫画を開いてみて</a>、そのソースで利用可能かどうか確認してください<br>2.<a href=kotatsu://about>最新版のこたつ</a><br>3.利用可能であれば、開発者にエラーレポートを送ってみてください。 + 人間工学に基づいたリーダーコントロール + 最近のマンガのショートカットを表示 + アプリケーションアイコンを長押しして最近のマンガを利用できるようにする + 右端をタップするか、右キーを押すと、常に次のページに切り替わります + 色補正 + 輝度 + コントラスト + リセット + 未保存の変更を保存または破棄しますか\? + 選択した色の設定は、この漫画のために記憶されます + 破棄 + デバイスに空き容量がありません + ページ切り替えスライダーを表示 + サーバーサイドエラー (%1$d) です。後で再試行してください + 新しいチャプターの情報も明確に + さまざまな言語 + ネットワークが利用できません + Wi-Fiまたはモバイルネットワークをオンにして、オンラインでマンガを読むことができます + Webtoonズーム + コンパクト + マミミ + + ここには何もありません + 読書の進捗状況を確認するには、マンガの詳細画面で「メニュー」→「追跡」を選択します。 + サービス + デバッグ目的でいくつかのアクションを記録する + ミク + ユーザー エージェント ヘッダー + コンテンツのプリロード + ログを共有 + 不安定な更新を許可 + アプリのベータ版へのアップデートを提案する + ダウンロードが開始されました + 言語 + ソースが無効になっています + 現在としてマーク + ログ記録を有効にする + 疑わしいコンテンツを表示する + ダイナミック + 配色 + グリッドビューで表示 + アスカ + ミオン + リッカ + さくら + この変更を適用するには、アプリケーションを再起動してください + 項目をタップ&ホールドして並び替えをすることができます + .cbzまたは.zipファイルを1つ以上選択することができ、各ファイルは別のマンガとして認識されます。 + 了解 + 翻訳 + 過去に作成したユーザーデータのバックアップをインポートする + 棚に表示 + %1$s (%2$s) + 色を反転させる + 有効 + 結構です + ネットワークキャッシュをクリアする + ダウンロードは削除されました + 自分で用意した同期サーバーか、デフォルトのものを使用することができます。よく分からない場合は変更しないでください。 + 一時停止 + ダウンロードがキャンセルされました + WebViewが利用できません:WebView providerがインストールされているかどうかを確認してください + ダウンロード済み + 画像最適化プロキシ + wsrv.nl サービスを使用して、トラフィック使用量を削減し、可能であれば画像の読み込みを高速化します + アーカイブや画像のあるディレクトリを選択することができます。各アーカイブ(またはサブディレクトリ)は、1つのチャプターとして認識されます。 + 類似したものを探す + タイプ + アドレス + ポート + プロキシ + 同期の設定 + サーバーアドレス + 速度 + SSLエラーを無視する + ミラーを自動的に選択する + ミラーがある場合、エラー時にリモートソースのドメインを自動で切り替える + 履歴書 + 一時停止 + 全てキャンセル + Wi-Fi経由でのみダウンロード + モバイルデータ通信への切り替え時にダウンロードを停止する + 提案: %s + 提案されたマンガの通知を表示することがあります + もっと見る + アクティブなダウンロードはすべてキャンセルされ、部分的にダウンロードされたデータは失われます + ダウンロード履歴は完全に削除されます + ダウンロードはありません + ダウンロードが再開されました + ダウンロードが一時停止されました + パーソナライズされた漫画の提案を受け取りますか? + 削除が完了 + 既存のアカウントにサインインするか、新規にアカウントを作成することができます + 無効な値 + ユーザー名 + パスワード + オーソライズ(オプション) + 無効なポート番号です + \ No newline at end of file From 0639d3e6c1cacc08eb0481edbe0fa4c8ce2f8764 Mon Sep 17 00:00:00 2001 From: Insopitus Date: Mon, 5 Jun 2023 11:53:37 +0200 Subject: [PATCH 43/94] Translated using Weblate (Chinese (Simplified)) Currently translated at 99.2% (413 of 416 strings) Co-authored-by: Insopitus Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/ Translation: Kotatsu/Strings --- app/src/main/res/values-zh-rCN/strings.xml | 794 +++++++++++---------- 1 file changed, 412 insertions(+), 382 deletions(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 62b5a3e00..5b20c9e2a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1,385 +1,415 @@ - 设置 - 本地存储 - 喜欢 - 历史 - 发生了一个错误 - 网络错误 - 章节 - 列表 - 数据被恢复了,但有错误 - 正在处理… - 最新 - 评分 - 已删除所有 cookie - 所有数据都被恢复了 - 无声 - 准备… - 未找到文件 - 昨日 - 你可以创建你的历史和收藏的备份并恢复它 - 现在 - 很久以前 - - 轻点以重试 - 所选择的配置将因这部漫画而被记住 - 需要验证码 - 解决 - 今天 - 清除cookies - 有新的漫画源可用 - 根据你的喜好推荐漫画 - 所有的数据都在这个设备上进行本地分析,不会发送到任何地方。 - 从不 - 你会收到你正在阅读的漫画的更新通知 - 18+ - 各种语言 - 查找章节 - 排除流派 - 建议更新 - 检查新的章节并通知有关情况 - 详细内容 - 详细列表 - 网格 - 列表模式 - 漫画源 - 加载中… - 计算中… - %1$d/%2$d章节 - 关闭 - 再试一次 - 清除历史 - 没有发现 - 尚无历史 - 阅读 - 尚无收藏夹 - 收藏此漫画 - 新分类 - 添加 - 保存 - 分享 - 创建快捷方式… - 分享%s - 搜索 - 搜索漫画 - 正在下载… - 已下载 - 下载 - 名称 - 热门 - 更新 - 排序顺序 - 过滤器 - 主题 - 深色 - 浅色 - 跟随系统 - 页数 - 清除 - 永久清除所有阅读历史\? - 删除 - \"%s\"从本地存储中删除 - 保存页面 - 保存 - 分享图片 - 导入 - 删除 - 不支持此操作 - 选择 ZIP 或 CBZ 文件. - 无描述 - 历史和缓存 - 清除页面缓存 - B|kB|MB|GB|TB - 标准 - 条漫 - 阅读模式 - 网格大小 - 在%s上搜索 - 删除漫画 - 从设备中永久删除\"%s\"\? - 阅读器设置 - 切换页面 - 音量按钮 - 继续 - 边缘点击 - 错误 - 清除缩略图缓存 - 清除搜索历史 - 清除 - 仅限手势 - 内部存储 - 外部存储 - 范围 - 新版本应用程序已经推出 - 在网络浏览器中打开 - 这部漫画有%s.全部保存\? - 保存 - 通知 - 新章节 - 下载 - 通知设置 - 通知声音 - LED指示器 - 振动 - 收藏夹分类 - 删除 - 这里有点空… - 尝试重新表述查询。 - 你所读的内容将在这里显示 - 在侧面菜单中找到要读的内容. - 先保存内容 - 从在线来源保存或导入文件. - 书架 - 最近 - 页面动画 - 下载文件夹 - 不详 - 没有可用的存储空间 - 其他存储 - 完成 - 所有收藏夹 - 空分类 - 稍后阅读 - 更新 - 你正在阅读的新章节显示在这里 - 搜索结果 - 新版本: %s - 清除更新源 - 已清除 - 旋转屏幕 - 更新 - 源更新即将开始 - 查找更新 - 不要检查 - 输入密码 - 密码错误 - 保护应用程序 - 在启动Kotatsu时要求输入密码 - 重复密码 - 密码不匹配 - 关于 - 版本%s - 检查更新 - 没有更新 - 从右到左 - 新分类 - 缩放模式 - 适应中心 - 适应高度 - 适应宽度 - 从头开始 - 黑色 - 在AMOLED屏幕上使用更少电池 - 备份和还原 - 创建数据备份 - 从备份中恢复 - 恢复 - 清除文件 - 永久地清除所有的更新历史? - 检查新的章节 - 撤销 - 登录 - 登录后可查看此内容 - 默认值: %s - 下一页 - 输入密码以启动应用程序 - 确认 - 密码必须是4个字符或以上 - 永久地删除所有最近的搜索查询? - 欢迎 - 保存备份 - 一些设备有不同的系统行为, 这可能会破坏后台任务. - 阅读更多 - 排队 - 下载或在线阅读这缺失的章节. - 该章缺失 - 翻译此应用程序 - 翻译 - 授权 - 不支持在%s上登录 - 你将退出登录所有来源 - 类型 - 连载中 - 已完结 - 默认 - 将NSFW漫画排除在历史之外 - 页数 - 使用图源 - 现有图源 - 屏幕截图 - 允许 - 禁止18+ - 始终阻止 - 建议 - 启用建议 - 开始阅读漫画,你会得到个性化的建议 - 请勿推荐18+漫画 - 启用 - 禁用 - 无法加载流派列表 - 重置过滤器 - 查找流派 - 选择你想看的漫画的语言. 你可以在以后的设置中改变它. - 只在Wi-Fi上使用 - 总是 - 预加载页面 - 以%s身份登录 - 这部漫画中没有章节 - 外观 - 内容 - 指定您不希望在建议中看到的类型 - 从设备中永久删除所选项目\? - 删除已完成 - 下载速度减慢 - 有助于避免阻断你的IP地址 - 保存的漫画处理 - 章节将在后台被删除 - 隐藏 - 你将不会收到通知但新的章节将在列表中突出显示 - 启用通知 - 命名 - 编辑 - 编辑分类 - 没有收藏夹分类 - 添加书签 - 删除书签 - 书签 - 删除书签 - 添加书签 - 撤销 - 从历史中删除 - DNS over HTTPS - 默认模式 - 自动检测阅读器模式 - 自动检测漫画是否为条漫 - 禁用电池优化 - 帮助进行背景更新检查 - 出了点问题. 请向开发人员提交一份错误报告以帮助我们修复它. - 发送 - 全部禁用 - 计划 - 暂停 - 报告 - 追踪 - 注销 - 阅读 - 重读 - 完成 - 使用指纹 - 你喜欢的漫画 - 您最近阅读的漫画 - 在历史和收藏夹中显示阅读百分比 - 显示阅读进度指标 - 数据删除 - 标记为NSFW的漫画将永远不会被添加到历史中你的进度也不会被保存 - 可以在出现一些问题时提供帮助. 所有授权将被视为无效 - 显示全部 - 错误详情:<br><tt>%1$s</tt><br><br>1.尝试<a href=%2$s>在网络浏览器中打开漫画</a>以确保在其来源中可用<br>2. 请确保您使用的是<a href=kotatsu://about>最新版本的Kotatsu</a><br>3.如果可用,请向开发人员发送错误报告。 - 无效域名 - 此处将显示你的漫画 - 在【浏览】页面搜索想要阅读的漫画 - %1$s%% - 已取消 - 账号已存在 - 返回 - 同步 - 同步您的数据 - 输入您的邮箱以继续 - 已放弃 - 选择范围 - 清除所有历史 - 过去2小时 - 书签已移除 - 历史已清除 - 管理 - 还没有书签 - 您可以在阅读漫画时创建书签 - 无漫画源 - 启用漫画源以在线阅读漫画 - 随机 - 您确定要删除选定的收藏夹吗? + 设置 + 本地存储 + 喜欢 + 历史 + 发生了一个错误 + 网络错误 + 章节 + 列表 + 数据被恢复了,但有错误 + 正在处理… + 最新 + 评分 + 已删除所有 cookie + 所有数据都被恢复了 + 无声 + 准备… + 未找到文件 + 昨日 + 你可以创建你的历史和收藏的备份并恢复它 + 现在 + 很久以前 + + 轻点以重试 + 所选择的配置将因这部漫画而被记住 + 需要验证码 + 解决 + 今天 + 清除cookies + 有新的漫画源可用 + 根据你的喜好推荐漫画 + 所有的数据都在这个设备上进行本地分析,不会发送到任何地方。 + 从不 + 你会收到你正在阅读的漫画的更新通知 + 18+ + 各种语言 + 查找章节 + 排除流派 + 建议更新 + 检查新的章节并通知有关情况 + 详细内容 + 详细列表 + 网格 + 列表模式 + 漫画源 + 加载中… + 计算中… + %1$d/%2$d章节 + 关闭 + 再试一次 + 清除历史 + 没有发现 + 尚无历史 + 阅读 + 尚无收藏夹 + 收藏此漫画 + 新分类 + 添加 + 保存 + 分享 + 创建快捷方式… + 分享%s + 搜索 + 搜索漫画 + 正在下载… + 已下载 + 下载 + 名称 + 热门 + 更新 + 排序顺序 + 过滤器 + 主题 + 深色 + 浅色 + 跟随系统 + 页数 + 清除 + 永久清除所有阅读历史\? + 删除 + \"%s\"从本地存储中删除 + 保存页面 + 保存 + 分享图片 + 导入 + 删除 + 不支持此操作 + 选择 ZIP 或 CBZ 文件. + 无描述 + 历史和缓存 + 清除页面缓存 + B|kB|MB|GB|TB + 标准 + 条漫 + 阅读模式 + 网格大小 + 在%s上搜索 + 删除漫画 + 从设备中永久删除\"%s\"\? + 阅读器设置 + 切换页面 + 音量按钮 + 继续 + 边缘点击 + 错误 + 清除缩略图缓存 + 清除搜索历史 + 清除 + 仅限手势 + 内部存储 + 外部存储 + 范围 + 新版本应用程序已经推出 + 在网络浏览器中打开 + 这部漫画有%s.全部保存\? + 保存 + 通知 + 新章节 + 下载 + 通知设置 + 通知声音 + LED指示器 + 振动 + 收藏夹分类 + 删除 + 这里有点空… + 尝试重新表述查询。 + 你所读的内容将在这里显示 + 在侧面菜单中找到要读的内容. + 先保存内容 + 从在线来源保存或导入文件. + 书架 + 最近 + 页面动画 + 下载文件夹 + 不详 + 没有可用的存储空间 + 其他存储 + 完成 + 所有收藏夹 + 空分类 + 稍后阅读 + 更新 + 你正在阅读的新章节显示在这里 + 搜索结果 + 新版本: %s + 清除更新源 + 已清除 + 旋转屏幕 + 更新 + 源更新即将开始 + 查找更新 + 不要检查 + 输入密码 + 密码错误 + 保护应用程序 + 在启动Kotatsu时要求输入密码 + 重复密码 + 密码不匹配 + 关于 + 版本%s + 检查更新 + 没有更新 + 从右到左 + 新分类 + 缩放模式 + 适应中心 + 适应高度 + 适应宽度 + 从头开始 + 黑色 + 在AMOLED屏幕上使用更少电池 + 备份和还原 + 创建数据备份 + 从备份中恢复 + 恢复 + 清除文件 + 永久地清除所有的更新历史? + 检查新的章节 + 撤销 + 登录 + 登录后可查看此内容 + 默认值: %s + 下一页 + 输入密码以启动应用程序 + 确认 + 密码必须是4个字符或以上 + 永久地删除所有最近的搜索查询? + 欢迎 + 保存备份 + 一些设备有不同的系统行为, 这可能会破坏后台任务. + 阅读更多 + 排队 + 下载或在线阅读这缺失的章节. + 该章缺失 + 翻译此应用程序 + 翻译 + 授权 + 不支持在%s上登录 + 你将退出登录所有来源 + 类型 + 连载中 + 已完结 + 默认 + 将NSFW漫画排除在历史之外 + 页数 + 使用图源 + 现有图源 + 屏幕截图 + 允许 + 禁止18+ + 始终阻止 + 建议 + 启用建议 + 开始阅读漫画,你会得到个性化的建议 + 请勿推荐18+漫画 + 启用 + 禁用 + 无法加载流派列表 + 重置过滤器 + 查找流派 + 选择你想看的漫画的语言. 你可以在以后的设置中改变它. + 只在Wi-Fi上使用 + 总是 + 预加载页面 + 以%s身份登录 + 这部漫画中没有章节 + 外观 + 内容 + 指定您不希望在建议中看到的类型 + 从设备中永久删除所选项目\? + 删除已完成 + 下载速度减慢 + 有助于避免阻断你的IP地址 + 保存的漫画处理 + 章节将在后台被删除 + 隐藏 + 你将不会收到通知但新的章节将在列表中突出显示 + 启用通知 + 命名 + 编辑 + 编辑分类 + 没有收藏夹分类 + 添加书签 + 删除书签 + 书签 + 删除书签 + 添加书签 + 撤销 + 从历史中删除 + DNS over HTTPS + 默认模式 + 自动检测阅读器模式 + 自动检测漫画是否为条漫 + 禁用电池优化 + 帮助进行背景更新检查 + 出了点问题. 请向开发人员提交一份错误报告以帮助我们修复它. + 发送 + 全部禁用 + 计划 + 暂停 + 报告 + 追踪 + 注销 + 阅读 + 重读 + 完成 + 使用指纹 + 你喜欢的漫画 + 您最近阅读的漫画 + 在历史和收藏夹中显示阅读百分比 + 显示阅读进度指标 + 数据删除 + 标记为NSFW的漫画将永远不会被添加到历史中你的进度也不会被保存 + 可以在出现一些问题时提供帮助. 所有授权将被视为无效 + 显示全部 + 错误详情:<br><tt>%1$s</tt><br><br>1.尝试<a href=%2$s>在网络浏览器中打开漫画</a>以确保在其来源中可用<br>2. 请确保您使用的是<a href=kotatsu://about>最新版本的Kotatsu</a><br>3.如果可用,请向开发人员发送错误报告。 + 无效域名 + 此处将显示你的漫画 + 在【浏览】页面搜索想要阅读的漫画 + %1$s%% + 已取消 + 账号已存在 + 返回 + 同步 + 同步您的数据 + 输入您的邮箱以继续 + 已放弃 + 选择范围 + 清除所有历史 + 过去2小时 + 书签已移除 + 历史已清除 + 管理 + 还没有书签 + 您可以在阅读漫画时创建书签 + 无漫画源 + 启用漫画源以在线阅读漫画 + 随机 + 您确定要删除选定的收藏夹吗? \n所有收藏夹中的漫画将丢失且无法恢复。 - 重新排序 - 留空 - 浏览 - 自动滚动 - 在阅读器中显示信息栏 - 漫画压缩包 - 图片文件夹 - 漫画导入中 - Ch. %1$d/%2$d Pg. %3$d/%4$d - %1$d 的 %2$d 启用 - 大小:%s - 再按一次返回键退出 - 按两次返回键退出应用 - 退出确认 - 已保存漫画 - 页面缓存 - 其他缓存 - 存储占用 - 可用 - 从收藏中移除 - 选项 - 隐身模式 - 无章节 - 导入完毕 - 您可以从存储中删除原文件以节省空间 - 即将开始导入 - 订阅源 - %s - %s - 内容未找到或已移除 - 点击屏幕右侧或按下右键翻到下一页 - 高效阅读器控制 - 长按应用图标显示最近阅读的漫画 - 显示最近阅读漫画的快捷方式 - 重置 - 颜色校正 - 亮度 - 对比度 - 所选颜色设置将会应用于此漫画 - 保存还是放弃未保存的更改? - 放弃 - 设备上没有剩余空间 - 显示换页滑块 - Webtoon 缩放 - 不同语言 - 网络不可用 - 打开 Wi-Fi 或移动网络在线阅读漫画 - 同样清除新章节信息 - 服务器端错误 (%1$d)。请稍后再试 - 紧凑 - 已禁用图源 - 内容预加载 - 标为当前 - 语言 - 启用日志记录 - 分享日志 - 出于调试目的记录某些操作 - 显示可疑内容 - 动态 - 颜色方案 - 用网格视图显示 - Miku - Asuka - Mion - Rikka - Sakura - 服务 - Mamimi - Kanade - 这里什么也没有 - 要跟踪阅读进度,在漫画详情屏幕上选中“菜单→ 跟踪。 - 允许不稳定更新 - 提示更新到测试版 - 已开始下载 - UserAgent 标头 - 要应用这些更改请重启程序 - 点击并长按项目排序 - 知道了 - 速度 - 导入先前创建的用户数据备份 - 在书架上显示 - 您可以选择一个或多个cbz或zip文件,每个文件都将识别为一个单独的漫画。 - 您可以选择一个包含压缩包或图片的文件夹。每个压缩包(或子文件夹)都会被识别为一个章节。 - + 重新排序 + 留空 + 浏览 + 自动滚动 + 在阅读器中显示信息栏 + 漫画压缩包 + 图片文件夹 + 漫画导入中 + Ch. %1$d/%2$d Pg. %3$d/%4$d + %1$d 的 %2$d 启用 + 大小:%s + 再按一次返回键退出 + 按两次返回键退出应用 + 退出确认 + 已保存漫画 + 页面缓存 + 其他缓存 + 存储占用 + 可用 + 从收藏中移除 + 选项 + 隐身模式 + 无章节 + 导入完毕 + 您可以从存储中删除原文件以节省空间 + 即将开始导入 + 订阅源 + %s - %s + 内容未找到或已移除 + 点击屏幕右侧或按下右键翻到下一页 + 高效阅读器控制 + 长按应用图标显示最近阅读的漫画 + 显示最近阅读漫画的快捷方式 + 重置 + 颜色校正 + 亮度 + 对比度 + 所选颜色设置将会应用于此漫画 + 保存还是放弃未保存的更改? + 放弃 + 设备上没有剩余空间 + 显示换页滑块 + Webtoon 缩放 + 不同语言 + 网络不可用 + 打开 Wi-Fi 或移动网络在线阅读漫画 + 同样清除新章节信息 + 服务器端错误 (%1$d)。请稍后再试 + 紧凑 + 已禁用图源 + 内容预加载 + 标为当前 + 语言 + 启用日志记录 + 分享日志 + 出于调试目的记录某些操作 + 显示可疑内容 + 动态 + 颜色方案 + 用网格视图显示 + Miku + Asuka + Mion + Rikka + Sakura + 服务 + Mamimi + Kanade + 这里什么也没有 + 要跟踪阅读进度,在漫画详情屏幕上选中“菜单→ 跟踪。 + 允许不稳定更新 + 提示更新到测试版 + 已开始下载 + UserAgent 标头 + 要应用这些更改请重启程序 + 点击并长按项目排序 + 知道了 + 速度 + 导入先前创建的用户数据备份 + 在书架上显示 + 您可以选择一个或多个cbz或zip文件,每个文件都将识别为一个单独的漫画。 + 您可以选择一个包含压缩包或图片的文件夹。每个压缩包(或子文件夹)都会被识别为一个章节。 + 寻找相似 + 翻译 + WebView不可用:检查是否已安装WebView + 你可以使用自建同步服务器或默认服务器。如果你不知道自己在干什么请不要修改此处。 + 自动选择镜像 + 如果存在可用镜像,在出错时自动切换域名 + 已暂停 + 切换到移动网络时停止下载 + 移除已完成 + 取消所有 + 仅通过Wi-Fi下载 + 启用 + 不,谢谢 + 同步设定 + 服务器地址 + 暂停 + 恢复 + 忽略SSL错误 + 没有下载项 + 下载已经恢复 + 暂停下载 + 下载已被移除 + 下载被取消 + 你想要接收个人漫画推荐吗? + 推荐:%s + 偶尔对建议的漫画显示通知 + 更多 + 所有进行中的下载都将被取消,未下载完成的数据将丢失 + 你的下载历史将会永久删除 + 你可以登陆一个已有账号或创建新账号 + \ No newline at end of file From 69a9ec354b6065f5f69afccf7cc591e5050d80cc Mon Sep 17 00:00:00 2001 From: InfinityDouki56 Date: Mon, 5 Jun 2023 11:53:37 +0200 Subject: [PATCH 44/94] Translated using Weblate (Filipino) Currently translated at 93.0% (387 of 416 strings) Co-authored-by: InfinityDouki56 Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/ Translation: Kotatsu/Strings --- app/src/main/res/values-fil/strings.xml | 796 ++++++++++++------------ 1 file changed, 412 insertions(+), 384 deletions(-) diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml index 9c510180a..75a3e1d2f 100644 --- a/app/src/main/res/values-fil/strings.xml +++ b/app/src/main/res/values-fil/strings.xml @@ -1,387 +1,415 @@ - Na-update - Pinakabago - Maliwanag - Marka - Pansala - Tema - Madilim - Sundan ang sistema - May nangyaring error - Error sa network - Mga detalye - Mga kabanata - Listahan - Na-save - I-share ang larawan - Mag-angkat - Tanggalin - Hindi suportado ang operasyong ito - Pumili ng ZIP o CBZ file. - Kasaysayan at cache - Walang paglalarawan - Laki ng grid - Hanapin sa %s - Tanggalin ang manga - Permanenteng tanggalin ang \"%s\" sa device\? - Mga setting sa pagbasa - Magpalit ng (mga) pahina - Pindutan ng volume - Magpatuloy - I-clear ang cache ng mga thumbnail - Na-clear - Mga kilos lang - Available ang isang bagong bersyon ng app - Buksan sa web browser - Ang manga na ito ay may %s. I-save ang lahat ng ito\? - Mga abiso - %1$d ng %2$d sa - Mga bagong kabanata - Subukang i-reformulate ang query. - Ang iyong nabasa ay ipapakita dito - Ang iyong manga ay ipapakita dito - Mag-save muna ng isang bagay - I-save ito mula sa mga online na source o mag import ng mga file. - Istante - Animasyon ng pahina - Hindi magagamit - Walang available na storage - Iba pang storage - Tapos na - Lahat ng paborito - Walang laman ang kategorya - Basahin mamaya - Mga update - Mga resulta ng paghahanap - Laki: %s - I-clear ang feed ng mga update - Na-clear - Update - Ang pag update ng feed ay magsisimula sa lalong madaling panahon - Maghanap ng mga update - Ilagay ang password - Humingi ng password kapag sinimulan ang Kotatsu - Tungkol rito - Maghanap ng update - Kanan sa kaliwa - Bagong Kategorya - Pagkasyahin sa gitna - Panatilihin sa simula - Gumagamit ng mas kaunting power sa mga AMOLED na screen - I-backup at i-restore - Naibalik na - Naghahanda… - Hindi nahanap ang file - Maaari kang lumikha ng backup ng iyong kasaysayan at mga paborito at ibalik ito - Ngayon lang - Kahapon - Matagal na ang nakalipas - Ngayong araw - I-tap para subukang muli - Lutasin - Inalis ang lahat ng mga cookie - I-clear ang feed - Suriin ang mga bagong kabanata - Mag-sign in - Mag-sign in upang tingnan ang nilalamang ito - Default: %s - Susunod - Kumpirmahin - Ang password ay dapat na 4 na character o higit pa - Maligayang pagdating - Na-save ang backup - Magbasa pa - Kulang ang kabanata - Ang pag-log in sa %s ay hindi suportado - Mga genre - Patuloy - Default - Hindi isali ang NSFW manga mula sa kasaysayan - Mga pahinang may bilang - Patakaran sa screenshot - Payagan - Palaging i-block - Mga mungkahi - Paganahin ang mga mungkahi - Simulan ang pagbabasa ng manga at makakakuha ka ng mga personalized na mungkahi - Huwag magmungkahi ng NSFW manga - Pinagana - Maghanap ng genre - Pumili ng mga wika na gusto mong basahin ang manga. Maaari mo itong baguhin sa ibang pagkakataon sa mga setting. - Lokal na storage - Mga paborito - Nakaraan - Mode na listahan - Detalyadong listahan - Grid - Mga setting - Mga remote na source - Naglo-load… - Isara - Walang nahanap - Tanggalin - Bagong Kategorya - Nabasa - Wala pang paborito - I-paborito ito - Idagdag - I-save - Ibahagi - Lumikha ng shortcut… - Ibahagi sa %s - Maghanap - Maghanap ng manga - Nagda-download… - Nagpoproseso… - Na-download - Mga download - Pangalan - Sikat - Mga pahina - I-clear ang kasaysayan - I-clear ang kasaysayan ng paghahanap - Bagong bersyon: %s - Hindi tumutugma sa mga password - I-clear ang mga cookie - I-clear ang page cache - I-save - I-download - Mga setting ng abiso - Tunog ng abiso - Mga paboritong kategorya - Tanggalin - Parang walang laman dito… - Hanapin kung ano ang babasahin sa side menu. - Hanapin kung ano ang babasahin sa seksyong «Mag-explore» - Kamakailan - Folder para sa mga download - I-save ang pahina - Natanggal ang \"%s\" sa lokal na storage - Wala pang kasaysayan - Permanenteng i-clear ang lahat ng kasaysayan ng pagbabasa\? - Huwag suriin - Ulitin ang password - Protektahan ang app - Maling password - Bersyon %s - Mode ng scale - Walang available na update - Baliktarin - Grupo - Tahimik - Pagkasyahin sa lapad - Itim - Lumikha ng data backup - Ibalik mula sa backup - Naibalik ang lahat ng data - Ang data ay naibalik, ngunit may mga error - Ang napiling pagsasaayos ay maaalala para sa manga na ito - Isalin ang app na ito - Awtorisado na - Kinakailangan ang CAPTCHA - I-clear nang permanente ang lahat ng update history\? - Maglagay ng password para simulan ang app - Ang ilang device ay may iba\'t ibang gawi ng system, na maaaring masira ang mga gawain sa background. - Nakapila na - I-download o basahin ang nawawalang kabanata online. - Mala-log out ka mula sa lahat ng source - Tapos na - Alisin ang lahat ng kamakailang query sa paghahanap nang permanente\? - Pagsasalin - I-block sa NSFW - Magmungkahi ng manga batay sa iyong mga kagustuhan - Ang lahat ng data ay sinusuri nang lokal sa aparatong ito. Walang paglipat ng iyong personal na data sa anumang mga serbisyo - Hindi pinagana - Hindi ma-load ang listahan ng mga genre - I-reset ang filter - Ang mga bagong kabanata ng iyong binabasa ay makikita dito - I-rotate ang screen - Pagkasyahin sa tangkad - Hindi kailanman - Sa Wi-Fi lang - Nagco-compute… - Kabanata %1$d ng %2$d - Subukan ulit - Pag-aayos ng order - I-clear - Mga taps ng gilid - Mga ginamit na source - Magagamit na mga source - Lagi na lang - I-preload ang mga pahina - Naka-log in bilang %s - Iba\'t ibang wika - Maghanap ng kabanata - %1$s%% - Hitsura - Hindi isali ang mga genre - Tukuyin ang mga genre na hindi mo nais na makita sa mga mungkahi - Nakumpleto na ang pagtanggal - Tumutulong na maiwasan ang pag-block ng iyong IP address - Naka-save na pagproseso ng manga - Mayroon nang account - Bumalik - Pag-synchronize - Ilagay ang iyong email upang magpatuloy - Itago - May mga bagong source ng manga - Hindi ka makakatanggap ng mga abiso ngunit ang mga bagong kabanata ay iha-highlight sa mga listahan - Paganahin ang mga abiso - Ayusin ang kategorya - Tina-track - Walang mga paboritong kategorya - Mag-log out - Magdagdag ng bookmark - Tinanggal ang bookmark - Inalis sa kasaysayan - DNS sa HTTPS - Default na mode - Automatikong matukoy ang reader mode - May nangyaring mali. Mangyaring magsumite ng isang bug report sa mga developer upang matulungan kaming ayusin ito. - Ipadala - Muling pagbabasa - Binitawan - Manga mula sa iyong mga paborito - Ang iyong kamakailang nabasa na manga - Pagtanggal ng data - Ipakita ang porsyento na nabasa sa kasaysayan at mga paborito - Ipakita lahat - Pumili ng saklaw - I-clear ang lahat ng kasaysayan - Maaari kang lumikha ng bookmark habang nagbabasa ng manga - Tinanggal ang mga bookmark - Random - Walang mga source ng manga - Paganahin ang mga source ng manga upang basahin ang manga online - Ayusin muli - Walang laman - Pindutin muli ang Bumalik upang lumabas - Pindutin ang Bumalik nang dalawang beses upang lumabas sa app - Pagkumpirma ng paglabas - Na-save na manga - Mag-Explore - Iba pang cache - Paggamit ng storage - Magagamit na - %s - %s - Inalis sa mga paborito - Mga pagpipilian - Incognito mode - Walang mga kabanata - Awtomatikong pag-scroll - Ch. %1$d/%2$d Pg. %3$d/%4$d - Ipakita ang information bar sa pagbasa - Archive ng mga comics - Folder na may mga larawan - Nakumpleto na ang pag-import - Magsisimula na ang pag-import - Feed - Gawing magagamit ang kamakailang manga sa pamamagitan ng mahabang pagpindot sa icon ng application - Ipakita ang mga kamakailang manga shortcut - Ergonomic na kontrol sa mambabasa - Pagwawasto ng kulay - Liwanag - Kaibahan - I-save o kalimutan ang mga hindi na-save na pagbabago\? - Kalimutan - Walang natitirang espasyo sa device - Pag-zoom sa webtoon - Iba\'t ibang wika - Server side error (%1$d). Subukang muli mamaya - I-clear din ang impormasyon tungkol sa mga bagong kabanata - Preloading ng nilalaman - Markahan bilang kasalukuyan - Wika - Ibahagi ang mga log - Magpakita ng kahina-hinalang nilalaman - Dynamic - Ipakita sa grid view - Asuka - Mion - Rikka - Sakura - Mamimi - Kanade - Wala naman dito - Mga serbisyo - Payagan ang mga hindi stable na update - Ipakita ang mga tagapagpahiwatig ng progress ng pagbabasa - Manga na minarkahan bilang NSFW ay hindi kailanman idadagdag sa kasaysayan at ang iyong progress ay hindi mase-save - Maaaring makatulong sa kaso ng ilang mga isyu. Ang lahat ng pahintulot ay mawawalan ng bisa - Imbalidong domain - Huling 2 oras - Nabura ang kasaysayan - Pamahalaan - Wala pang bookmark - 18+ - Hindi natagpuan o inalis ang nilalaman - Magtala ng ilang pagkilos para sa mga layunin ng pag-debug - Permanenteng tanggalin ang mga napiling item sa device\? - Walang mga kabanata sa manga na ito - Nag-a-update ang mga mungkahi - Nilalaman - Pagbagal ng pag-download - Tatanggalin ang mga chapters sa background. Maaari itong tumagal ng ilang oras - Kinansela - I-sync ang iyong data - Tingnan ang mga bagong kabanata at ipaalam ang tungkol dito - Pangalan - I-edit - Tanggalin ang bookmark - Makakatanggap ka ng mga abiso tungkol sa mga update ng manga na iyong binabasa - Mag-undo - Nagbabasa - Cache ng mga pahina - Mga bookmark - Sigurado ka bang gusto mong tanggalin ang mga napiling paboritong kategorya\? + Na-update + Pinakabago + Maliwanag + Marka + Pansala + Tema + Madilim + Sundan ang sistema + May nangyaring error + Error sa network + Mga detalye + Mga kabanata + Listahan + Na-save + I-share ang larawan + Mag-angkat + Tanggalin + Hindi suportado ang operasyong ito + Pumili ng ZIP o CBZ file. + Kasaysayan at cache + Walang paglalarawan + Laki ng grid + Hanapin sa %s + Tanggalin ang manga + Permanenteng tanggalin ang \"%s\" sa device\? + Mga setting sa pagbasa + Magpalit ng (mga) pahina + Pindutan ng volume + Magpatuloy + I-clear ang cache ng mga thumbnail + Na-clear + Mga kilos lang + Available ang isang bagong bersyon ng app + Buksan sa web browser + Ang manga na ito ay may %s. I-save ang lahat ng ito\? + Mga abiso + %1$d ng %2$d sa + Mga bagong kabanata + Subukang i-reformulate ang query. + Ang iyong nabasa ay ipapakita dito + Ang iyong manga ay ipapakita dito + Mag-save muna ng isang bagay + I-save ito mula sa mga online na source o mag import ng mga file. + Istante + Animasyon ng pahina + Hindi magagamit + Walang available na storage + Iba pang storage + Tapos na + Lahat ng paborito + Walang laman ang kategorya + Basahin mamaya + Mga update + Mga resulta ng paghahanap + Laki: %s + I-clear ang feed ng mga update + Na-clear + Update + Ang pag update ng feed ay magsisimula sa lalong madaling panahon + Maghanap ng mga update + Ilagay ang password + Humingi ng password kapag sinimulan ang Kotatsu + Tungkol rito + Maghanap ng update + Kanan sa kaliwa + Bagong Kategorya + Pagkasyahin sa gitna + Panatilihin sa simula + Gumagamit ng mas kaunting power sa mga AMOLED na screen + I-backup at i-restore + Naibalik na + Naghahanda… + Hindi nahanap ang file + Maaari kang lumikha ng backup ng iyong kasaysayan at mga paborito at ibalik ito + Ngayon lang + Kahapon + Matagal na ang nakalipas + Ngayong araw + I-tap para subukang muli + Lutasin + Inalis ang lahat ng mga cookie + I-clear ang feed + Suriin ang mga bagong kabanata + Mag-sign in + Mag-sign in upang tingnan ang nilalamang ito + Default: %s + Susunod + Kumpirmahin + Ang password ay dapat na 4 na character o higit pa + Maligayang pagdating + Na-save ang backup + Magbasa pa + Kulang ang kabanata + Ang pag-log in sa %s ay hindi suportado + Mga genre + Patuloy + Default + Hindi isali ang NSFW manga mula sa kasaysayan + Mga pahinang may bilang + Patakaran sa screenshot + Payagan + Palaging i-block + Mga mungkahi + Paganahin ang mga mungkahi + Simulan ang pagbabasa ng manga at makakakuha ka ng mga personalized na mungkahi + Huwag magmungkahi ng NSFW manga + Pinagana + Maghanap ng genre + Pumili ng mga wika na gusto mong basahin ang manga. Maaari mo itong baguhin sa ibang pagkakataon sa mga setting. + Lokal na storage + Mga paborito + Kasaysayan + Mode na listahan + Detalyadong listahan + Grid + Mga setting + Mga source ng Manga + Naglo-load… + Isara + Walang nahanap + Tanggalin + Bagong Kategorya + Nabasa + Wala pang paborito + I-paborito ito + Idagdag + I-save + Ibahagi + Lumikha ng shortcut… + Ibahagi sa %s + Maghanap + Maghanap ng manga + Nagda-download… + Nagpoproseso… + Na-download + Mga download + Pangalan + Sikat + Mga pahina + I-clear ang kasaysayan + I-clear ang kasaysayan ng paghahanap + Bagong bersyon: %s + Hindi tumutugma sa mga password + I-clear ang mga cookie + I-clear ang page cache + I-save + I-download + Mga setting ng abiso + Tunog ng abiso + Mga paboritong kategorya + Tanggalin + Parang walang laman dito… + Hanapin kung ano ang babasahin sa side menu. + Hanapin kung ano ang babasahin sa seksyong «Mag-explore» + Kamakailan + Folder para sa mga download + I-save ang pahina + Natanggal ang \"%s\" sa lokal na storage + Wala pang kasaysayan + Permanenteng i-clear ang lahat ng kasaysayan ng pagbabasa\? + Huwag suriin + Ulitin ang password + Protektahan ang app + Maling password + Bersyon %s + Mode ng scale + Walang available na update + Baliktarin + Grupo + Tahimik + Pagkasyahin sa lapad + Itim + Lumikha ng data backup + Ibalik mula sa backup + Naibalik ang lahat ng data + Ang data ay naibalik, ngunit may mga error + Ang napiling pagsasaayos ay maaalala para sa manga na ito + Isalin ang app na ito + Awtorisado na + Kinakailangan ang CAPTCHA + I-clear nang permanente ang lahat ng update history\? + Maglagay ng password para simulan ang app + Ang ilang device ay may iba\'t ibang gawi ng system, na maaaring masira ang mga gawain sa background. + Nakapila na + I-download o basahin ang nawawalang kabanata online. + Mala-log out ka mula sa lahat ng source + Tapos na + Alisin ang lahat ng kamakailang query sa paghahanap nang permanente\? + Pagsasalin + I-block sa NSFW + Magmungkahi ng manga batay sa iyong mga kagustuhan + Ang lahat ng data ay lokal lamang na sinusuri sa device na ito at hindi kailanman ipinadala kahit saan. + Hindi pinagana + Hindi ma-load ang listahan ng mga genre + I-reset ang filter + Ang mga bagong kabanata ng iyong binabasa ay makikita dito + I-rotate ang screen + Pagkasyahin sa tangkad + Hindi kailanman + Sa Wi-Fi lang + Nagco-compute… + Kabanata %1$d ng %2$d + Subukan ulit + Pag-aayos ng order + I-clear + Mga taps ng gilid + Mga ginamit na source + Magagamit na mga source + Lagi na lang + I-preload ang mga pahina + Naka-log in bilang %s + Iba\'t ibang wika + Maghanap ng kabanata + %1$s%% + Hitsura + Hindi isali ang mga genre + Tukuyin ang mga genre na hindi mo nais na makita sa mga mungkahi + Nakumpleto na ang pagtanggal + Tumutulong na maiwasan ang pag-block ng iyong IP address + Naka-save na pagproseso ng manga + Mayroon nang account + Bumalik + Pag-synchronize + Ilagay ang iyong email upang magpatuloy + Itago + May mga bagong source ng manga + Hindi ka makakatanggap ng mga abiso ngunit ang mga bagong kabanata ay iha-highlight sa mga listahan + Paganahin ang mga abiso + Ayusin ang kategorya + Tina-track + Walang mga paboritong kategorya + Mag-log out + Magdagdag ng bookmark + Tinanggal ang bookmark + Inalis sa kasaysayan + DNS sa HTTPS + Default na mode + Automatikong matukoy ang reader mode + May nangyaring mali. Mangyaring magsumite ng isang bug report sa mga developer upang matulungan kaming ayusin ito. + Ipadala + Muling pagbabasa + Binitawan + Manga mula sa iyong mga paborito + Ang iyong kamakailang nabasa na manga + Pagtanggal ng data + Ipakita ang porsyento na nabasa sa kasaysayan at mga paborito + Ipakita lahat + Pumili ng saklaw + I-clear ang lahat ng kasaysayan + Maaari kang lumikha ng bookmark habang nagbabasa ng manga + Tinanggal ang mga bookmark + Random + Walang mga source ng manga + Paganahin ang mga source ng manga upang basahin ang manga online + Ayusin muli + Walang laman + Pindutin muli ang Bumalik upang lumabas + Pindutin ang Bumalik nang dalawang beses upang lumabas sa app + Pagkumpirma ng paglabas + Na-save na manga + Mag-Explore + Iba pang cache + Paggamit ng storage + Magagamit na + %s - %s + Inalis sa mga paborito + Mga pagpipilian + Incognito mode + Walang mga kabanata + Awtomatikong pag-scroll + Ch. %1$d/%2$d Pg. %3$d/%4$d + Ipakita ang information bar sa pagbasa + Archive ng mga comics + Folder na may mga larawan + Nakumpleto na ang pag-import + Magsisimula na ang pag-import + Feed + Gawing magagamit ang kamakailang manga sa pamamagitan ng mahabang pagpindot sa icon ng application + Ipakita ang mga kamakailang manga shortcut + Ergonomic na kontrol sa mambabasa + Pagwawasto ng kulay + Liwanag + Kaibahan + I-save o kalimutan ang mga hindi na-save na pagbabago\? + Kalimutan + Walang natitirang espasyo sa device + Pag-zoom sa webtoon + Iba\'t ibang wika + Server side error (%1$d). Subukang muli mamaya + I-clear din ang impormasyon tungkol sa mga bagong kabanata + Preloading ng nilalaman + Markahan bilang kasalukuyan + Wika + Ibahagi ang mga log + Magpakita ng kahina-hinalang nilalaman + Dynamic + Ipakita sa grid view + Asuka + Mion + Rikka + Sakura + Mamimi + Kanade + Wala naman dito + Mga serbisyo + Payagan ang mga hindi stable na update + Ipakita ang mga tagapagpahiwatig ng progress ng pagbabasa + Manga na minarkahan bilang NSFW ay hindi kailanman idadagdag sa kasaysayan at ang iyong progress ay hindi mase-save + Maaaring makatulong sa kaso ng ilang mga isyu. Ang lahat ng pahintulot ay mawawalan ng bisa + Imbalidong domain + Huling 2 oras + Nabura ang kasaysayan + Pamahalaan + Wala pang bookmark + 18+ + Hindi natagpuan o inalis ang nilalaman + Magtala ng ilang pagkilos para sa mga layunin ng pag-debug + Permanenteng tanggalin ang mga napiling item sa device\? + Walang mga kabanata sa manga na ito + Nag-a-update ang mga mungkahi + Nilalaman + Pagbagal ng pag-download + Tatanggalin ang mga kabanata sa background + Kinansela + I-sync ang iyong data + Tingnan ang mga bagong kabanata at ipaalam ang tungkol dito + Pangalan + I-edit + Tanggalin ang bookmark + Makakatanggap ka ng mga abiso tungkol sa mga update ng manga na iyong binabasa + Mag-undo + Nagbabasa + Cache ng mga pahina + Mga bookmark + Sigurado ka bang gusto mong tanggalin ang mga napiling paboritong kategorya\? \nAng lahat ng manga sa loob nito ay mawawala at hindi na ito mababawi. - Idinagdag ang bookmark - Awtomatikong matukoy kung ang manga ay webtoon - Huwag paganahin ang pag-optimize ng baterya - Tumutulong sa mga pagsusuri sa mga update sa background - Nakaplano - Nakumpleto na - Naka-hold - Huwag paganahin ang lahat - Gumamit ng fingerprint kung magagamit - Ulat - I-reset - Magmungkahi ng mga update sa mga beta na bersyon ng app - Hindi magagamit ang network - I-on ang Wi-Fi o mobile network para magbasa ng manga online - Mag-tap sa kanang gilid o ang pagpindot sa kanang key ay palaging lilipat sa susunod na pahina - Ipakita ang slider ng paglipat ng pahina - Mga detalye ng error:<br><tt>%1$s</tt><br><br>1. Subukang <a href=%2$s>buksan ang manga sa isang web browser</a> upang matiyak na magagamit ito sa source<br>nito 2. Kung magagamit ito, magpadala ng isang ulat ng error sa mga developer. - Paganahin ang pag-log - Hindi pinagana ang source - Pag-import ng manga - Maaari mong tanggalin ang orihinal na file mula sa storage upang makatipid ng espasyo - Ang napiling mga setting ng kulay ay matatandaan para sa manga na ito - Compact - Upang subaybayan ang pag unlad ng pagbabasa, piliin ang Menu → Track sa screen ng mga detalye ng manga. - Nagsimula na ang pag-download - Scheme ng kulay - Miku - Header ng UserAgent - B|kB|MB|GB|TB - Standard - Webtoon - Read mode - Error - Internal storage - External storage - Vibration - Domain - LED indicator - Mangyaring i-restart ang application upang ilapat ang mga pagbabagong ito - Nakuha ko - I-tap at hawakan ang isang aytem upang muling ayusin ang mga ito - Mag-import ng dating ginawa na backup ng data ng user - Ipakita sa Istante - Bilis - Maaari kang pumili ng isa o higit pang .cbz o .zip file, ang bawat file ay makikilala bilang isang hiwalay na manga. - Maaari kang pumili ng isang directory na may mga archive o mga larawan. Ang bawat archive (o subdirectory) ay makikilala bilang isang kabanata. - Maghanap ng katulad - Maaari kang mag-sign in sa isang umiiral na account o lumikha ng bago - + Idinagdag ang bookmark + Awtomatikong matukoy kung ang manga ay webtoon + Huwag paganahin ang pag-optimize ng baterya + Tumutulong sa mga pagsusuri sa mga update sa background + Nakaplano + Nakumpleto na + Naka-hold + Huwag paganahin ang lahat + Gumamit ng fingerprint kung magagamit + Ulat + I-reset + Magmungkahi ng mga update sa mga beta na bersyon ng app + Hindi magagamit ang network + I-on ang Wi-Fi o mobile network para magbasa ng manga online + Mag-tap sa kanang gilid o ang pagpindot sa kanang key ay palaging lilipat sa susunod na pahina + Ipakita ang slider ng paglipat ng pahina + Mga detalye ng error:<br><tt>%1$s</tt><br><br>1. Subukang <a href=%2$s>magbukas ng manga sa isang web browser</a> upang matiyak na available ito sa souce<br>2. Tiyaking ginagamit mo ang <a href=kotatsu://about>pinakabagong bersyon ng Kotatsu</a><br>3. Kung available ito, magpadala ng ulat ng error sa mga developer. + Paganahin ang pag-log + Hindi pinagana ang source + Pag-import ng manga + Maaari mong tanggalin ang orihinal na file mula sa storage upang makatipid ng espasyo + Ang napiling mga setting ng kulay ay matatandaan para sa manga na ito + Compact + Upang subaybayan ang pag unlad ng pagbabasa, piliin ang Menu → Track sa screen ng mga detalye ng manga. + Nagsimula na ang pag-download + Scheme ng kulay + Miku + Header ng UserAgent + B|kB|MB|GB|TB + Standard + Webtoon + Read mode + Error + Internal storage + External storage + Vibration + Domain + LED indicator + Mangyaring i-restart ang application upang ilapat ang mga pagbabagong ito + Nakuha ko + I-tap at hawakan ang isang aytem upang muling ayusin ang mga ito + Mag-import ng dating ginawa na backup ng data ng user + Ipakita sa Istante + Bilis + Maaari kang pumili ng isa o higit pang .cbz o .zip file, ang bawat file ay makikilala bilang isang hiwalay na manga. + Maaari kang pumili ng isang directory na may mga archive o mga larawan. Ang bawat archive (o subdirectory) ay makikilala bilang isang kabanata. + Maghanap ng katulad + Maaari kang mag-sign in sa isang umiiral na account o lumikha ng bago + Mga pagsasalin + Hindi available ang WebView: tingnan kung naka-install ang WebView provider + Paganahin + Na-pause ang mga pag-download + Mga setting ng pag-synchronize + Address ng server + Maaari kang gumamit ng self-hosted synchronization server o isang default. Huwag baguhin ito kung hindi ka sigurado sa iyong ginagawa. + Huwag pansinin ang mga error sa SSL + Awtomatikong pumili ng mirror + Awtomatikong lumipat ng mga domain para sa mga remote source sa mga error kung available ang mga mirror + Kanselahin lahat + Mag-download lamang sa pamamagitan ng Wi-Fi + Itigil ang pag-download kapag lumipat sa isang mobile network + Naka-pause + Tanggalin ang nakumpleto na + Mga mungkahi: %s + I-pause + Minsang magpakita ng mga notification na may iminungkahing manga + Higit pa + Salamat nalang + Ipagpatuloy + Ang lahat ng mga aktibong pag download ay kakanselahin, bahagyang na download na data ay mawawala + Permanenteng ide-delete ang iyong history ng mga pag-download + Wala kang anumang mga pag-download + Ipinagpatuloy ang mga pag-download + Gusto mo bang makatanggap ng personalized na mga mungkahi sa manga\? + Inalis na ang mga download + Nakansela ang mga pag-download + \ No newline at end of file From 8ac95e1608bed2276e68fc860e724dfc3ab782bd Mon Sep 17 00:00:00 2001 From: tryvseu Date: Mon, 5 Jun 2023 11:53:38 +0200 Subject: [PATCH 45/94] Translated using Weblate (Norwegian Nynorsk) Currently translated at 85.5% (356 of 416 strings) Co-authored-by: tryvseu Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/nn/ Translation: Kotatsu/Strings --- app/src/main/res/values-nn/strings.xml | 707 +++++++++++++------------ 1 file changed, 359 insertions(+), 348 deletions(-) diff --git a/app/src/main/res/values-nn/strings.xml b/app/src/main/res/values-nn/strings.xml index 28c7e9b36..905125266 100644 --- a/app/src/main/res/values-nn/strings.xml +++ b/app/src/main/res/values-nn/strings.xml @@ -1,351 +1,362 @@ - Det hende ein feil - Rutenett - Innstillingar - Mangakjelder - Tøm historikken - Historikken er tom - Les - Lik - Ny hop - Legg til - Hent - Lag ein snarveg … - Del %s - Søk - Søk manga - Hentar … - Handsamar … - Henta - Nyaste - Omdøme - Sil ut - Ljos - Sider - Tøm - Tøm lesehistorikken for godt\? - Tak bort - Hent sida - Henta - Del biletet - Før inn - Slett - Vel ei ZIP- eller CBZ-fil. - Ingen utgreiing - Tøm mellomminnet til sida - Vanleg - Nettserie - Rutenettstorleik - Slett mangaen - Slett «%s» ifrå eininga\? - Leseinnstillingar - Bla med - Hald fram - Feil - Tøm mellomminnet for småbilete - Tøm søkehistorikken - Tømt - Berre handrørsler - Hent - Varsel - %1$d av %2$d - Hent - Varselinnstillingar - Varselljod - Varselljos - Dirring - Hopar til leiting - Hent ifrå nettkjelder eller før inn filer. - Hylla - Nytt - Legg henta mangaar i: - Gjort - Alt du likar - Tom hop - Les seinare - Oppdateringar - Søkesvar - Ny utgåve: %s - Tømt - Snu skjermen - Leit etter oppdateringar - Nei - Om - Leit etter oppdateringar - Høgre-til-venstre - Lesevising - Høv til høgda - Høv til breidda - Svart - Tryggleikskopiering og gjenoppretting - Lag ein tryggleikskopi - Gjenoppretta - Fann ikkje fila - Gjenoppretta all data - Gjenoppretta dataa, men med feil - Trykk for å røyna att - Listeslag - Henta - Likar - Historikk - Nettverksfeil - Liste - Hentar fram … - Steng - Røyn att - Fann ikkje noko - Del - Henta - Namn - Oppdatert - Vising - Lyd systemet - Mørk - Historikken og mellomminnet - Hent noko først - Ikkje tilgjengeleg - Oppdater - Storleik: %s - Brukar mindre straum på AMOLED-skjermar - Utgåve %s - Ingen tilgjengelege oppdateringar - Ny hop - Midtstill - Auk byrjinga av sida - Gjenopprett ifrå ein tryggleikskopi - Du kan tryggleikskopiera historikken og likerlista di til seinare gjenoppretting - Førebur … - Forval - No - I dag - I går - Lenge sida - Lesing - Randetrykk - Ljodstyrkeknappar - Ei ny utgåve av appen er tilgjengeleg - Opne i ein nettlesar - Denne mangaen har %s. Hent alle\? - Det du les vert vist her - Rit inn lykelordet - Gjentak lykelordet - Lykelorda er ulike - Brigde av oppsettet vedkjem berre denne mangaen - Stille - Krev CAPTCHA - Løys - Slett infokapslane - Sletta infokapslane - Tøm oppdateringshistorikken\? - Logg inn - Neste - Stadfest - Lykelordet må vera lengre enn fire teikn - Tryggleikskopi laga - Les meir - I kø - Omset denne appen - Omsetjing - Godkjend - Slag - Fullgjort - I gang - Utelèt mangaar med vakse innhald ifrå historikken - Sidetal - Nytta kjelder - Tilgjengelege kjelder - Skjermbilete - Hindre alltid - Råd - Slå på råd - Rå om mangaar ut ifrå det du har lese - Byrja å lesa nokre mangaar for å få personlege råd - Ikkje rå mangaar med vakse innhald - Påslegen - Kunne ikkje hente inn slaglista - Finn slag - Ulike mål - %1$s%% - Innhald - Oppdaterer råd - Utelat slag - Sletta - Avgrens hentesnøggleiken - Lægjer vona for at IP-adressa di vert blokkert - Handsamar henta manga - Avbroten - Kontoen finst alt - Attende - Synkroniser dataet ditt - Rit inn e-postadressa di for å halda fram - Skjul - Namn - Brigd - Brigd hopen - Sporing - Ingen likte hopar - Logg ut - Bokmerk - Tak bort bokmerket - Bokmerke - Teken bort ifrå historikken - DNS over HTTPS - Forvald lesing - Finn sjølvverkande ut av lesing - Finn sjølvverkande ut av om mangaen er ein nettserie - Slå av batterilenging - Send - Les - Skal lesa - Les att - Lesen - På vent - Gjeven opp - Slå av alle - Mangaar du har nyleg lese - Sletting av data - Vis % lesen i historikken og likerlista - Kan løysa nokre feil. Alle godkjenningar vert ugilde - Vis alle - Ugildt domene - Vel område - Tøm heile historikken - Tømte historikken - Ingen bokmerke endå - Du kan lage bokmerke medan du les - Tok bort bokmerka - Ingen mangakjelder - Slå på minst ei mangakjelde for å lesa mangaar på nett - Tilfeldig - Flytt - Tom - Trykk Attende att for å gå or appen - Utgåingsstadfesting - Mellominnet for sider - Mellomminnet for anna - Tilgjengeleg - %s - %s - Teken or likerlista - Fann ikkje innhaldet - Bla sjølvverkande - Teikneseriearkiv - Mappe med bilete - Fører inn manga - Brigd letar - Ljosstyrk - Still attende - Spar eller avvis dei usparte brigda\? - Avvis - Eininga er fylt - Vis ei rulleline til blading - Auk/mink nettseriar - Ulike mål - Nettverk ikkje tilgjengeleg - Slå på Wi-Fi eller mobilnettverk for å lesa mangaar på nett - Tjenarfeil (%1$d). Røyn att seinare - Kjelde avslegen - Hent inn innhald på forhand - Merk som aktuelt - Mål - Del loggføringar - Slå på loggføring - Tak opp nokre gjerder til bruk i istandsetjing. - Skiftande - Letar - Vis som rutenett - Rikka - Asuka - Sakura - Mamimi - Kanade - Ingenting her - Tenester - Har byrja å hente - Tøm søkehistorikken\? - Velkomen - Du vert logga ut ifrå alle kjeldane - Hindre ved vakse innhald - Slett - Her var det tomt … - Spør om lykelordet ved byrjing av appen - Feil lykelord - Vern appen - Logg inn for å sjå dette innhaldet - Vern appen med eit lykelord - All data vert handsama på eininga di og vert ikkje førte over til noka teneste - Avslegen - Vel måla du vil lesa mangaar på. Du kan brigde på dette seinare i innstillingane. - Aldri - Berre på Wi-Fi - 18+ - Alltid - Hent sider på forhand - Utsjånad - Slett valde ting ifrå eininga di\? - Logga inn som %s - Opplys om kva slags slag du ikkje vil få råd om - Synkronisering - Nye mangakjelder tilgjengelege - Du kjem til å få varsel når mangaar du les vert oppdaterte - Slå på varsel - La til eit bokmerke - Tok bort bokmerket - Angre - Nytt fingermerke om tilgjengeleg - Vis leseframgang - Mangaar du likar - Mangaar merkte med vakse innhald vert ikkje lagde til i historikken din, og framgangen din vert ikkje spart - Slett dei valde hopane\? + Det hende ein feil + Rutenett + Innstillingar + Mangakjelder + Tøm historikken + Historikken er tom + Les + Lik + Ny hop + Legg til + Hent + Lag ein snarveg … + Del %s + Søk + Søk manga + Hentar … + Handsamar … + Henta + Nyaste + Omdøme + Sil ut + Ljos + Sider + Tøm + Tøm lesehistorikken for godt\? + Tak bort + Hent sida + Henta + Del biletet + Før inn + Slett + Vel ei ZIP- eller CBZ-fil. + Ingen utgreiing + Tøm mellomminnet til sida + Vanleg + Nettserie + Rutenettstorleik + Slett mangaen + Slett «%s» ifrå eininga\? + Leseinnstillingar + Bla med + Hald fram + Feil + Tøm mellomminnet for småbilete + Tøm søkehistorikken + Tømt + Berre handvendingar + Hent + Varsel + %1$d av %2$d + Hent + Varselinnstillingar + Varselljod + Varselljos + Dirring + Hopar til leiting + Hent ifrå nettkjelder eller før inn filer. + Hylla + Nytt + Legg henta mangaar i: + Ferdig + Alt du likar + Tom hop + Les seinare + Oppdateringar + Søkesvar + Ny utgåve: %s + Tømt + Snu skjermen + Leit etter oppdateringar + Nei + Om + Leit etter oppdateringar + Høgre-til-venstre + Lesevising + Høv til høgda + Høv til breidda + Svart + Tryggleikskopiering og gjenoppretting + Lag ein tryggleikskopi + Gjenoppretta + Fann ikkje fila + Gjenoppretta all data + Gjenoppretta dataa, men med feil + Trykk for å røyna att + Listeslag + Henta + Likar + Historikk + Nettverksfeil + Liste + Hentar fram … + Steng + Røyn att + Fann ikkje noko + Del + Henta + Namn + Oppdatert + Vising + Lyd systemet + Mørk + Historikken og mellomminnet + Hent noko først + Ikkje tilgjengeleg + Oppdater + Storleik: %s + Brukar mindre straum på AMOLED-skjermar + Utgåve %s + Ingen tilgjengelege oppdateringar + Ny hop + Midtstill + Auk byrjinga av sida + Gjenopprett ifrå ein tryggleikskopi + Du kan tryggleikskopiera historikken og likerlista di til seinare gjenoppretting + Førebur … + Forval + No + I dag + I går + Lenge sida + Lesing + Randetrykk + Ljodstyrkeknappar + Ei ny utgåve av appen er tilgjengeleg + Opne i ein nettlesar + Denne mangaen har %s. Hent alle\? + Det du les vert vist her + Rit inn lykelordet + Gjentak lykelordet + Lykelorda er ulike + Brigde av oppsettet vedkjem berre denne mangaen + Stille + Krev CAPTCHA + Løys + Slett infokapslane + Sletta infokapslane + Tøm oppdateringshistorikken\? + Logg inn + Neste + Stadfest + Lykelordet må vera lengre enn fire teikn + Tryggleikskopi laga + Les meir + I kø + Omset denne appen + Omsetjing + Godkjend + Slag + Fullgjort + I gang + Utelèt mangaar med vakse innhald ifrå historikken + Sidetal + Nytta kjelder + Tilgjengelege kjelder + Skjermbilete + Hindre alltid + Råd + Slå på råd + Rå om mangaar ut ifrå det du har lese + Byrja å lesa nokre mangaar for å få personlege råd + Ikkje rå mangaar med vakse innhald + Påslegen + Kunne ikkje hente inn slaglista + Finn slag + Ulike mål + %1$s%% + Innhald + Oppdaterer råd + Utelat slag + Sletta + Avgrens hentesnøggleiken + Lægjer vona for at IP-adressa di vert blokkert + Handsamar henta manga + Avbroten + Kontoen finst alt + Attende + Synkroniser dataet ditt + Rit inn e-postadressa di for å halda fram + Skjul + Namn + Brigd + Brigd hopen + Sporing + Ingen likte hopar + Logg ut + Bokmerk + Tak bort bokmerket + Bokmerke + Teken bort ifrå historikken + DNS over HTTPS + Forvald lesing + Finn sjølvverkande ut av lesing + Finn sjølvverkande ut av om mangaen er ein nettserie + Slå av batterilenging + Send + Les + Skal lesa + Les att + Lesen + På vent + Gjeven opp + Slå av alle + Mangaar du har nyleg lese + Sletting av data + Vis % lesen i historikken og likerlista + Kan løysa nokre feil. Alle godkjenningar vert ugilde + Vis alle + Ugildt domene + Vel område + Tøm heile historikken + Tømte historikken + Ingen bokmerke endå + Du kan lage bokmerke medan du les + Tok bort bokmerka + Ingen mangakjelder + Slå på minst ei mangakjelde for å lesa mangaar på nett + Tilfeldig + Flytt + Tom + Trykk Attende att for å gå or appen + Utgåingsstadfesting + Mellominnet for sider + Mellomminnet for anna + Tilgjengeleg + %s - %s + Teken or likerlista + Fann ikkje innhaldet + Bla sjølvverkande + Teikneseriearkiv + Mappe med bilete + Fører inn manga + Brigd letar + Ljosstyrk + Still attende + Spar eller avvis dei usparte brigda\? + Avvis + Eininga er fylt + Vis ei rulleline til blading + Auk/mink nettseriar + Ulike mål + Nettverk ikkje tilgjengeleg + Slå på Wi-Fi eller mobilnettverk for å lesa mangaar på nett + Tjenarfeil (%1$d). Røyn att seinare + Kjelde avslegen + Hent inn innhald på forhand + Merk som aktuelt + Mål + Del loggføringar + Slå på loggføring + Tak opp nokre gjerder til bruk i istandsetjing. + Skiftande + Letar + Vis som rutenett + Rikka + Asuka + Sakura + Mamimi + Kanade + Ingenting her + Tenester + Har byrja å hente + Tøm søkehistorikken\? + Velkomen + Du vert logga ut ifrå alle kjeldane + Hindre ved vakse innhald + Slett + Her var det tomt … + Spør om lykelordet ved byrjing av appen + Feil lykelord + Vern appen + Logg inn for å sjå dette innhaldet + Vern appen med eit lykelord + All data vert handsama på eininga di og vert ikkje førte over til noka teneste + Avslegen + Vel måla du vil lesa mangaar på. Du kan brigde på dette seinare i innstillingane. + Aldri + Berre på Wi-Fi + 18+ + Alltid + Hent sider på forhand + Utsjånaden + Slett valde ting ifrå eininga di\? + Logga inn som %s + Opplys om kva slags slag du ikkje vil få råd om + Synkronisering + Nye mangakjelder tilgjengelege + Du kjem til å få varsel når mangaar du les vert oppdaterte + Slå på varsel + La til eit bokmerke + Tok bort bokmerket + Angre + Nytt fingermerke om tilgjengeleg + Vis leseframgang + Mangaar du likar + Mangaar merkte med vakse innhald vert ikkje lagde til i historikken din, og framgangen din vert ikkje spart + Slett dei valde hopane\? \nDu kan ikkje angre. Alle mangaane inni vert tekne ut av likerlista. - Innstillingar - Dei siste to timane - Handsam - Trykk Attende to gongar for å gå or appen - Henta mangaar - Privat modus - Førte inn - Slett den opphavlege fila for å frigjera rom - Byrjar å føra inn snart - Motsetjing - Brigde av letane vedkjem berre denne mangaen - Vis mistenksamt innhald - Mion - Miku - Byrja om appen for å nytta desse brigda - Kapittel - Utreknar… - Kapittel %1$d av %2$d - Ustødd gjerd - B|kB|MB|GB|TB - Domene - Nye kapittel - Mangaane dine vert viste her - Siderørsle - Nye kapittel av det du les vert viste her - Sjå etter nye kapittel - Siste øvst - Nokre einingar har systemåtferd som kan knuse bakgrunnsføreloger. - Hent eller les dette saknande kapittelet på nettet. - Saknar kapittelet - Finn kapittel - Ingen kapittel i denne mangaen - Kapittel vert teken bort i bakgrunnen - Sjå etter og varsle om nye kapittel - Nye kapittel vert merkte i listene utan varsel - Gransk - Ingen kapittel - Ka. %1$d/%2$d Side %3$d/%4$d - Vis opplysingsområde i lesevisinga - Trykk på høgre side eller ljodstyrke-ned-knappen blar alltid til neste side - Samantrengt - Vis i hylla - Før inn ei tryggleikskopi av brukardata - Du kan velja ei mappe med arkiv eller bilete. Kvart arkiv (eller undermappe) vert tydde som eit kapittel. - Snøggleik - Vel ei eller fleire .cbz eller .zip-filer, kvar fil vert tydde som ein eigen manga. - Tøm au opplysingar om nye kapittel - Trykk «Meny → Spor» på ei mangadetaljside for å spore leseframdrifta. - Skjønar - Trykk og hald på eit element for å flytta på det - + Innstillingar + Dei siste to timane + Handsam + Trykk Attende to gongar for å gå or appen + Henta mangaar + Privat modus + Førte inn + Slett den opphavlege fila for å frigjera rom + Byrjar å føra inn snart + Motsetjing + Brigde av letane vedkjem berre denne mangaen + Vis mistenksamt innhald + Mion + Miku + Byrja om appen for å nytta desse brigda + Kapittel + Utreknar… + Kapittel %1$d av %2$d + Ustødd gjerd + B|kB|MB|GB|TB + Domene + Nye kapittel + Mangaane dine vert viste her + Siderørsle + Nye kapittel av det du les vert viste her + Sjå etter nye kapittel + Siste øvst + Nokre einingar har systemåtferd som kan knuse bakgrunnsføreloger. + Hent eller les dette saknande kapittelet på nettet. + Saknar kapittelet + Finn kapittel + Ingen kapittel i denne mangaen + Kapittel vert teken bort i bakgrunnen + Sjå etter og varsle om nye kapittel + Nye kapittel vert merkte i listene utan varsel + Gransk + Ingen kapittel + Ka. %1$d/%2$d Side %3$d/%4$d + Vis opplysingsområde i lesevisinga + Trykk på høgre side eller ljodstyrke-ned-knappen blar alltid til neste side + Samantrengt + Vis i hylla + Før inn ei tryggleikskopi av brukardata + Du kan velja ei mappe med arkiv eller bilete. Kvart arkiv (eller undermappe) vert tydde som eit kapittel. + Snøggleik + Vel ei eller fleire .cbz eller .zip-filer, kvar fil vert tydde som ein eigen manga. + Tøm au opplysingar om nye kapittel + Trykk «Meny → Spor» på ei mangadetaljside for å spore leseframdrifta. + Skjønar + Trykk og hald på eit element for å flytta på det + Sletta «%s» ifrå eininga + Indre gøyme + Ytre gøyme + Ingen tilgjengelege gøyme + Anna gøyme + Røyn å skriva det om. + Ingen likte enno + Mest lest for tida + Søk på %s + Finn lesnadar i sidemenyen. + Finn lesnadar i «Gransk»-delen + \ No newline at end of file From c6228d3fe18b97794642205193fbfb36d3a3243f Mon Sep 17 00:00:00 2001 From: Subham Jena Date: Mon, 5 Jun 2023 11:53:38 +0200 Subject: [PATCH 46/94] Translated using Weblate (Odia) Currently translated at 7.3% (31 of 421 strings) Translated using Weblate (Odia) Currently translated at 5.5% (23 of 416 strings) Co-authored-by: Subham Jena Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/or/ Translation: Kotatsu/Strings --- app/src/main/res/values-or/strings.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index d8db4f084..b55162b4b 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -11,4 +11,19 @@ ଥିମ୍ ଵେଗ ଡାଉନଲୋଡ୍ ଆରମ୍ଭ ହେଲା + ପାଠକ ସେଟିଂ + ଵିଜ୍ଞପ୍ତି + ଥାକ + ସର୍ଵଦା + ଵିଷୟଵସ୍ତୁ + ଵିଜ୍ଞପ୍ତି ସେଟିଂ + ରୂପ + ଯାଞ୍ଚ କରନି + ଅଦ୍ୟତନ ପାଇଁ ଯାଞ୍ଚ କରିବା + ଗତକାଲି + ଆଜି + ନୂଆ ଅଧ୍ୟାୟ ପାଇଁ ଯାଞ୍ଚ କରି ଏହା ଵିଷୟରେ ସୂଚିତ କରିବା + ନୂଆ ଅଧ୍ୟାୟ ପାଇଁ ଯାଞ୍ଚ କରିବା + ଫାଇଲ ମିଳୁନାହିଁ + ବ୍ୟାକଅପ୍ ଓ ପୁନରୁଦ୍ଧାର \ No newline at end of file From 96b6900c7001057cba55e44c195ca0f812527f49 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Mon, 5 Jun 2023 11:53:39 +0200 Subject: [PATCH 47/94] Translated using Weblate (Spanish) Currently translated at 100.0% (430 of 430 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (422 of 422 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (421 of 421 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (7 of 7 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (417 of 417 strings) Co-authored-by: gallegonovato Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/es/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/ Translation: Kotatsu/Strings Translation: Kotatsu/plurals --- app/src/main/res/values-es/plurals.xml | 6 +++--- app/src/main/res/values-es/strings.xml | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-es/plurals.xml b/app/src/main/res/values-es/plurals.xml index 3deb92806..f5f4a4cbb 100644 --- a/app/src/main/res/values-es/plurals.xml +++ b/app/src/main/res/values-es/plurals.xml @@ -1,9 +1,9 @@ - Total de %1$d página - Total de %1$d páginas - Total de %1$d páginas + Página total %1$d + Páginas totales %1$d + Página totales %1$d %1$d elemento diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 613c1c1f1..ae1169138 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -412,4 +412,18 @@ ¿Quieres recibir sugerencias sobre mangas personalizadas\? Traducciones WebView no está disponible: comprueba si el proveedor de WebView está instalado + Borrar la caché de la red + Tipo + Dirección + Puerto + Proxy + Valor no válido + %1$s (%2$s) + Optimización de imágenes proxy + Nombre de usuario + Descargado + Autorización (opcional) + Utiliza el servicio wsrv.nl para reducir el uso del tráfico y acelerar la carga de imágenes si es posible + Contraseña + Invertir los colores \ No newline at end of file From ff2cf9d18a558fea131f100c48ba90c79870f0d2 Mon Sep 17 00:00:00 2001 From: Bai Date: Mon, 5 Jun 2023 11:53:39 +0200 Subject: [PATCH 48/94] Translated using Weblate (Turkish) Currently translated at 100.0% (431 of 431 strings) Translated using Weblate (Turkish) Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Turkish) Currently translated at 99.7% (416 of 417 strings) Co-authored-by: Bai Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/ Translation: Kotatsu/Strings --- app/src/main/res/values-tr/strings.xml | 802 +++++++++++++------------ 1 file changed, 427 insertions(+), 375 deletions(-) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index e5685c1b8..fdefd45bb 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -1,378 +1,430 @@ - Ağ hatası - Dahili Depolama - Favoriler - Geçmiş - Bölümler - Liste - Detaylı liste - Izgara - Liste modu - Yükleniyor… - Kapat - Tekrar dene - Geçmişi temizle - Hiçbir şey bulunamadı - Geçmiş yok - Oku - Henüz favorileriniz yok - Favoriniz - Yeni kategori - Ekle - Kaydet - Paylaş - %s Paylaş - Ara - Manga ara - İndiriliyor… - İşleniyor… - İndirildi - İndirilenler - Ad - Güncellenme - Yeniler - Puanlama - Litre - Tema - Açık - Koyu - Takip sistemi - Sayfalar - Temizle - Tüm okuma geçmişi kalıcı olarak silinsin mi\? - Kaldır - “%s” yerel depolama alanından sil - Sayfayı kaydet - Resmi paylaş - Popüler - Detaylar - Ayarlar - Kaydet - Bir hata oluştu - Uzak kaynaklar - Geçmiş ve önbellek - Temizlendi - Devam - Müsait değil - Boş kategori - Kaldır - Sil - Bölüm %1$d / %2$d - Bir ZIP veya CBZ dosyası seçin. - Okuma modu - Izgara boyutu - Webtoon - B|kB|MB|GB|TB - Okuyucu ayarları - Ses butonları - Hata - Küçük resim önbelleğini temizle - Yalnızca hareketler - Alan adi - Web tarayıcısında aç - Yeni bölümler - Bildirim ayarları - Bildirim sesi - LED göstergesi - Titreşim - Diğer depolama - Güncellemeler - Kısayol oluştur… - İçe aktar - Mangayı sil - Bilgi işleniyor… - Sıralama düzeni - Açıklama yok - Bu işlem desteklenmiyor - Standart - Sayfa önbelleğini temizle - %s üzerinde ara - Dahili depolama - Bildirimler - Sayfaları değiştir - Kaydet - İndir - İndirilenler klasörü - Harici depolama - Uygulamanın yeni bir sürümü mevcut - Favori kategoriler - Bitti - Sonra oku - Sayfa animasyonu - Kullanılabilir depolama alanı yok - “%s” cihazdan kalıcı olarak silinsin mi\? - Arama geçmişini temizle - Burası biraz boş… - Ekranı döndür - Ölçek modu - Yüksekliğe sığdır - Siyah - Başlangıçta tut - Akışı temizle - Bu eksik bölümü çevrim içi olarak indirin veya okuyun. - Yedekten geri yükle - Güncelle - Oturum aç - Bitti - Hakkında - Bu içeriği görüntülemek için oturum açın - Onayla - Yetkilendirildi - Az önce - Kenar dokunuşları - Bu mangada %s var. Hepsi kaydedilsin mi\? - %1$d / %2$d açık - Sorguyu yeniden biçimlendirmeyi deneyin. - Okuduklarınız burada görüntülenecek - Yan menüde ne okuyacağınızı bulun. - Önce bir şey kaydedin - Çevrim içi kaynaklardan kaydedin veya dosyaları içe aktarın. - Raf - Son - Boyut: %s - Temizlendi - Parola gir - Kotatsu başlatılırken parola sor - Güncellemeleri ara - Güncelleme akışını temizle - Akış güncellemesi yakında başlayacak - Sürüm %s - Güncellemeleri denetle - Merkeze sığdır - Genişliğe sığdır - AMOLED ekranlarda daha az güç kullanır - Yedekle ve geri yükle - Veri yedeği oluştur - Geri yüklendi - Hazırlanıyor… - Dün - Grup - Sessiz - Çöz - Çerezleri temizle - Öntanımlı: %s - Ters - Parola 4 veya daha fazla karakterden oluşmalıdır - Hoş geldiniz - Sıraya alındı - Bölüm eksik - Bu uygulamayı çevirin - Çeviri - Devam ediyor - Tüm kaynaklardaki oturumunuz kapatılacak - Kullanılan kaynaklar - Kullanılabilir kaynaklar - Uygunsuz mangayı geçmişten hariç tut - Numaralı sayfalar - Arama sonuçları - Parolayı tekrarla - Denetleme - Yanlış parola - Geçmişinizin ve favorilerinizin yedeğini oluşturabilir ve bunları geri yükleyebilirsiniz - Uzun zaman önce - Bugün - Güncelleme yok - Tüm favoriler - Okuduklarınızın yeni bölümleri burada gösterilir - Yeni sürüm: %s - Uygulamayı koru - Parolalar eşleşmiyor - Sağdan-sola - Yeni kategori - Dosya bulunamadı - Tüm veriler geri yüklendi - Veriler geri yüklendi, ancak hatalar var - Tekrar denemek için dokunun - İleri - CAPTCHA gerekli - Tüm çerezler kaldırıldı - Seçilen yapılandırma bu manga için hatırlanacak - Tüm güncelleme geçmişi kalıcı olarak silinsin mi\? - Uygulamayı başlatmak için bir parola girin - Tüm son arama sorguları kalıcı olarak kaldırılsın mı\? - Yedek kaydedildi - Türler - Öntanımlı - %s üzerinde oturum açma desteklenmiyor - Daha fazla oku - Bazı aygıtların arka plan görevlerini bozabilecek farklı sistem davranışları vardır. - Ekran görüntüsü politikası - Uygunsuzlarda engelle - Her zaman engelle - İzin ver - Yeni bölümleri denetle - Öneriler - Önerileri etkinleştir - Tercihlerinize göre manga önerileri alın - Tüm veriler aygıt üzerinde yerel olarak işlenir. Kişisel verilerinizin herhangi bir hizmete aktarılması söz konusu değildir - Manga okumaya başladıktan sonra kişiselleştirilmiş öneriler alacaksınız - Uygunsuz manga önerme - Etkin - Devre dışı - Türler listesi yüklenemiyor - Filtreyi sıfırla - Tür bul - Manga okumak istediğiniz dilleri seçin. Daha sonra ayarlardan değiştirebilirsiniz. - Her zaman - Hiçbir zaman - Yalnızca Wi-Fi\'de - Sayfaları önceden yükle - %s olarak oturum açıldı - 18+ - Çeşitli diller - Bölüm bul - Bu mangada bölüm yok - %%%1$s - İçerik - Öneriler güncelleniyor - Görünüm - Türleri hariç tut - Önerilerde görmek istemediğiniz türleri belirtin - Seçilen ögeler aygıttan kalıcı olarak silinsin mi\? - Kaldırma tamamlandı - Bölümler arka planda kaldırılacaktır. Bu biraz zaman alabilir - İndirmeyi yavaşlat - IP adresinizin engellenmesinden kaçınmanıza yardımcı olur - Kaydedilen manga işleme - Gizle - Yeni manga kaynakları var - Bildirim almayacaksınız ancak yeni bölümler listelerde vurgulanacak - Bildirimleri etkinleştir - Yeni bölümleri denetle ve bildirim gönder - Okuduğunuz manga güncellemeleri hakkında bildirim alacaksınız - Favori kategori yok - Ad - Düzenle - Kategoriyi düzenle - Yer imi ekle - Yer imini kaldır - Yer imleri - Yer imi kaldırıldı - Yer imi eklendi - Geri al - Geçmişten kaldırıldı - HTTPS üzerinden DNS - Okuyucu modunu otomatik algıla - Manganın webtoon olup olmadığını otomatik olarak algıla - Öntanımlı mod - Pil iyileştirmesini devre dışı bırak - Arka planda güncelleme denetimlerine yardımcı olur - Bir şeyler yanlış gitti. Düzeltmemize yardımcı olması için lütfen geliştiricilere bir hata bildirimi gönderin. - Gönder - Tümünü devre dışı bırak - Varsa parmak izi kullan - Favorilerinizden mangalar - Son okuduğunuz mangalar - Bildir - İzleme - Oturumu kapat - Okunuyor - Tamamlandı - Okuma ilerleme göstergelerini göster - Verileri sil - Geçmişte ve favorilerde okunma yüzdesini göster - Uygunsuz olarak işaretlenen mangalar asla geçmişe eklenmeyecek ve ilerlemeniz kaydedilmeyecektir - Bazı sorunlarda yardımcı olabilir. Tüm yetkilendirmeler geçersiz kılınacaktır - Beklemede - Bırakıldı - Planlandı - Yeniden okunuyor - Tümünü göster - Geçersiz etki alanı - Aralık seç - İçerik bulunamadı veya kaldırıldı - Manganız burada görüntülenecek - İptal edilmiş - Hesap zaten var - Geri - Senkronizasyon - Verini yedekle - Devam etmek için E-Postanızı girin - Tüm gecmişi temizle - Son 2 saat - Geçmiş temizlendi - Yönet - Yer işareti yok - Manga okurken yer işareti oluşturabilirsiniz - Yer işaretleri kaldırıldı - Manga kaynağı yok - Çevrimiçi manga okumak için manga kaynaklarını aktif edin - Rastgele - Boş - Keşfet - Çıkmak için tekrar Geri tıkla - Çıkmak için iki defa Geri tıkla - Favorilerden kaldırıldı - Çıkış doğrulaması - Çizgi roman arşivi - Hata ayrıntıları:<br><tt>%1$s</tt><br><br>1.Mangayı <a href=%2$s>kaynağında mevcut olduğuna emin olmak için</a> bir web tarayıcısında açın<br>2. Mevcutsa, geliştiricilere bir hata reporu gönderin. - «Keşfet» kısmında neler okuyacağınızı bulun - Seçilen favori kategorileri silmek istediğinizden emin misiniz\? + Ağ hatası + Dahili Depolama + Favoriler + Geçmiş + Bölümler + Liste + Detaylı liste + Izgara + Liste modu + Yükleniyor… + Kapat + Tekrar dene + Geçmişi temizle + Hiçbir şey bulunamadı + Geçmiş yok + Oku + Henüz favorileriniz yok + Favoriniz + Yeni kategori + Ekle + Kaydet + Paylaş + %s Paylaş + Ara + Manga ara + İndiriliyor… + İşleniyor… + İndirildi + İndirilenler + Ad + Güncellenme + Yeniler + Puanlama + Litre + Tema + Açık + Koyu + Takip sistemi + Sayfalar + Temizle + Tüm okuma geçmişi kalıcı olarak silinsin mi\? + Kaldır + “%s” yerel depolama alanından sil + Sayfayı kaydet + Resmi paylaş + Popüler + Detaylar + Ayarlar + Kaydet + Bir hata oluştu + Manga kaynakları + Geçmiş ve önbellek + Temizlendi + Devam + Müsait değil + Boş kategori + Kaldır + Sil + Bölüm %1$d / %2$d + Bir ZIP veya CBZ dosyası seçin. + Okuma modu + Izgara boyutu + Webtoon + B|kB|MB|GB|TB + Okuyucu ayarları + Ses butonları + Hata + Küçük resim önbelleğini temizle + Yalnızca hareketler + Alan adi + Web tarayıcısında aç + Yeni bölümler + Bildirim ayarları + Bildirim sesi + LED göstergesi + Titreşim + Diğer depolama + Güncellemeler + Kısayol oluştur… + İçe aktar + Mangayı sil + Bilgi işleniyor… + Sıralama düzeni + Açıklama yok + Bu işlem desteklenmiyor + Standart + Sayfa önbelleğini temizle + %s üzerinde ara + Dahili depolama + Bildirimler + Sayfaları değiştir + Kaydet + İndir + İndirilenler klasörü + Harici depolama + Uygulamanın yeni bir sürümü mevcut + Favori kategoriler + Bitti + Sonra oku + Sayfa animasyonu + Kullanılabilir depolama alanı yok + “%s” cihazdan kalıcı olarak silinsin mi\? + Arama geçmişini temizle + Burası biraz boş… + Ekranı döndür + Ölçek modu + Yüksekliğe sığdır + Siyah + Başlangıçta tut + Akışı temizle + Bu eksik bölümü çevrim içi olarak indirin veya okuyun. + Yedekten geri yükle + Güncelle + Oturum aç + Bitti + Hakkında + Bu içeriği görüntülemek için oturum açın + Onayla + Yetkilendirildi + Az önce + Kenar dokunuşları + Bu mangada %s var. Hepsi kaydedilsin mi\? + %1$d / %2$d açık + Sorguyu yeniden biçimlendirmeyi deneyin. + Okuduklarınız burada görüntülenecek + Yan menüde ne okuyacağınızı bulun. + Önce bir şey kaydedin + Çevrim içi kaynaklardan kaydedin veya dosyaları içe aktarın. + Raf + Son + Boyut: %s + Temizlendi + Parola gir + Kotatsu başlatılırken parola sor + Güncellemeleri ara + Güncelleme akışını temizle + Akış güncellemesi yakında başlayacak + Sürüm %s + Güncellemeleri denetle + Merkeze sığdır + Genişliğe sığdır + AMOLED ekranlarda daha az güç kullanır + Yedekle ve geri yükle + Veri yedeği oluştur + Geri yüklendi + Hazırlanıyor… + Dün + Grup + Sessiz + Çöz + Çerezleri temizle + Öntanımlı: %s + Ters + Parola 4 veya daha fazla karakterden oluşmalıdır + Hoş geldiniz + Sıraya alındı + Bölüm eksik + Bu uygulamayı çevirin + Çeviri + Devam ediyor + Tüm kaynaklardaki oturumunuz kapatılacak + Kullanılan kaynaklar + Kullanılabilir kaynaklar + Uygunsuz mangayı geçmişten hariç tut + Numaralı sayfalar + Arama sonuçları + Parolayı tekrarla + Denetleme + Yanlış parola + Geçmişinizin ve favorilerinizin yedeğini oluşturabilir ve bunları geri yükleyebilirsiniz + Uzun zaman önce + Bugün + Güncelleme yok + Tüm favoriler + Okuduklarınızın yeni bölümleri burada gösterilir + Yeni sürüm: %s + Uygulamayı koru + Parolalar eşleşmiyor + Sağdan-sola + Yeni kategori + Dosya bulunamadı + Tüm veriler geri yüklendi + Veriler geri yüklendi, ancak hatalar var + Tekrar denemek için dokunun + İleri + CAPTCHA gerekli + Tüm çerezler kaldırıldı + Seçilen yapılandırma bu manga için hatırlanacak + Tüm güncelleme geçmişi kalıcı olarak silinsin mi\? + Uygulamayı başlatmak için bir parola girin + Tüm son arama sorguları kalıcı olarak kaldırılsın mı\? + Yedek kaydedildi + Türler + Öntanımlı + %s üzerinde oturum açma desteklenmiyor + Daha fazla oku + Bazı aygıtların arka plan görevlerini bozabilecek farklı sistem davranışları vardır. + Ekran görüntüsü politikası + Uygunsuzlarda engelle + Her zaman engelle + İzin ver + Yeni bölümleri denetle + Öneriler + Önerileri etkinleştir + Tercihlerinize göre manga önerileri alın + Tüm veriler sadece bu cihaz üzerinde yerel olarak işlenir ve asla herhangi bir yere satılmaz. + Manga okumaya başladıktan sonra kişiselleştirilmiş öneriler alacaksınız + Uygunsuz manga önerme + Etkin + Devre dışı + Türler listesi yüklenemiyor + Filtreyi sıfırla + Tür bul + Manga okumak istediğiniz dilleri seçin. Daha sonra ayarlardan değiştirebilirsiniz. + Her zaman + Hiçbir zaman + Yalnızca Wi-Fi\'de + Sayfaları önceden yükle + %s olarak oturum açıldı + 18+ + Çeşitli diller + Bölüm bul + Bu mangada bölüm yok + %%%1$s + İçerik + Öneriler güncelleniyor + Görünüm + Türleri hariç tut + Önerilerde görmek istemediğiniz türleri belirtin + Seçilen ögeler aygıttan kalıcı olarak silinsin mi\? + Kaldırma tamamlandı + Bölümler arka planda kaldırılacak. + İndirmeyi yavaşlat + IP adresinizin engellenmesinden kaçınmanıza yardımcı olur + Kaydedilen manga işleme + Gizle + Yeni manga kaynakları var + Bildirim almayacaksınız ancak yeni bölümler listelerde vurgulanacak + Bildirimleri etkinleştir + Yeni bölümleri denetle ve bildirim gönder + Okuduğunuz manga güncellemeleri hakkında bildirim alacaksınız + Favori kategori yok + Ad + Düzenle + Kategoriyi düzenle + Yer imi ekle + Yer imini kaldır + Yer imleri + Yer imi kaldırıldı + Yer imi eklendi + Geri al + Geçmişten kaldırıldı + HTTPS üzerinden DNS + Okuyucu modunu otomatik algıla + Manganın webtoon olup olmadığını otomatik olarak algıla + Öntanımlı mod + Pil iyileştirmesini devre dışı bırak + Arka planda güncelleme denetimlerine yardımcı olur + Bir şeyler yanlış gitti. Düzeltmemize yardımcı olması için lütfen geliştiricilere bir hata bildirimi gönderin. + Gönder + Tümünü devre dışı bırak + Varsa parmak izi kullan + Favorilerinizden mangalar + Son okuduğunuz mangalar + Bildir + İzleme + Oturumu kapat + Okunuyor + Tamamlandı + Okuma ilerleme göstergelerini göster + Verileri sil + Geçmişte ve favorilerde okunma yüzdesini göster + Uygunsuz olarak işaretlenen mangalar asla geçmişe eklenmeyecek ve ilerlemeniz kaydedilmeyecektir + Bazı sorunlarda yardımcı olabilir. Tüm yetkilendirmeler geçersiz kılınacaktır + Beklemede + Bırakıldı + Planlandı + Yeniden okunuyor + Tümünü göster + Geçersiz etki alanı + Aralık seç + İçerik bulunamadı veya kaldırıldı + Manganız burada görüntülenecek + İptal edilmiş + Hesap zaten var + Geri + Senkronizasyon + Verini yedekle + Devam etmek için E-Postanızı girin + Tüm gecmişi temizle + Son 2 saat + Geçmiş temizlendi + Yönet + Yer işareti yok + Manga okurken yer işareti oluşturabilirsiniz + Yer işaretleri kaldırıldı + Manga kaynağı yok + Çevrimiçi manga okumak için manga kaynaklarını aktif edin + Rastgele + Boş + Keşfet + Çıkmak için tekrar Geri tıkla + Çıkmak için iki defa Geri tıkla + Favorilerden kaldırıldı + Çıkış doğrulaması + Çizgi roman arşivi + Hata ayrıntıları:<br><tt>%1$s</tt><br><br>1.Mangayı <a href=%2$s>kaynağında mevcut olduğuna emin olmak için</a> bir web tarayıcısında açın<br>2. <a href=kotatsu://about> Kotatsunun son sürümünü kullandığnızdan emin olun.</a>/br> 3. Mevcutsa, geliştiricilere bir hata reporu gönderin. + «Keşfet» kısmında neler okuyacağınızı bulun + Seçilen favori kategorileri silmek istediğinizden emin misiniz\? \nİçindeki tüm mangalar kaybolur ve bu işlem geri alınamaz. - Yeniden sırala - Sayfa önbelleği - Diğer önbellekler - Depolama kullanımı - Mevcut - %s - %s - Seçenekler - Gizli mod - Bölüm yok - Otomatik kaydır - Böl. %1$d/%2$d Sayf. %3$d/%4$d - Okuyucuda bilgi çubuğu göster - Resimlerle klasör - Manga içe aktarılıyor - İçe aktarım tamamlandı - Yer açmak için orijinal dosyayı depolamadan silebilirsiniz - İçe aktarım birazdan başlayacak - Akış - En son manga kısayollarını göster - Ergonomik okuyucu kontrol - Renk düzeltme - Parlaklık - Kontrast - Sıfırla - Seçilen renk ayarları bu manga için hatırlanacaktır - Kaydedilmeyen değişiklikler kaydedilsin mi yoksa atılsın mı\? - Yoksay - Cihazda yer yok - Webtoon yakınlaştırma - Sayfa değiştirme kaydırıcısını göster - Ayrıca yeni bölümler hakkındaki bilgileri temizle - Sıkı - Farklı diller - Ağ kullanılamıyor - Çevrim içi manga okumak için Wi-Fi veya mobil ağı açın - Sunucu tarafı hatası (%1$d). Lütfen daha sonra tekrar deneyin - Kaydedilen mangalar - Uygulama simgesine uzun basarak son mangaları kullanılabilir hale getirin - Sağ kenara dokunulduğunda veya sağ tuşa basıldığında her zaman bir sonraki sayfaya geçilir - Kaynak devre dışı - İçerik ön yüklemesi - Geçerli olarak işaretle - Dil - Günlükleri paylaş - Günlük kaydını etkinleştir - Hata ayıklama amacıyla bazı eylemleri kaydedin - Şüpheli içeriği göster - Hizmetler - Okuma ilerlemesini izlemek için manga ayrıntıları ekranında Menü → İzle\'yi seçin. - burada hiçbir şey yok - Dinamik - renk vurgusu - Izgara görünümünde göster - Mamimi - Kanade - UserAgent başlığı - Uygulamanın beta sürümleri için güncellemeler öner - Kararsız güncellemelere izin ver - İndirme başladı - Miku - Asuka - Mion - Rikka - Sakura - Bu değişiklikleri uygulamak için lütfen uygulamayı yeniden başlatın - + Yeniden sırala + Sayfa önbelleği + Diğer önbellekler + Depolama kullanımı + Mevcut + %s - %s + Seçenekler + Gizli mod + Bölüm yok + Otomatik kaydır + Böl. %1$d/%2$d Sayf. %3$d/%4$d + Okuyucuda bilgi çubuğu göster + Resimlerle klasör + Manga içe aktarılıyor + İçe aktarım tamamlandı + Yer açmak için orijinal dosyayı depolamadan silebilirsiniz + İçe aktarım birazdan başlayacak + Akış + En son manga kısayollarını göster + Ergonomik okuyucu kontrol + Renk düzeltme + Parlaklık + Kontrast + Sıfırla + Seçilen renk ayarları bu manga için hatırlanacaktır + Kaydedilmeyen değişiklikler kaydedilsin mi yoksa atılsın mı\? + Yoksay + Cihazda yer yok + Webtoon yakınlaştırma + Sayfa değiştirme kaydırıcısını göster + Ayrıca yeni bölümler hakkındaki bilgileri temizle + Sıkı + Farklı diller + Ağ kullanılamıyor + Çevrim içi manga okumak için Wi-Fi veya mobil ağı açın + Sunucu tarafı hatası (%1$d). Lütfen daha sonra tekrar deneyin + Kaydedilen mangalar + Uygulama simgesine uzun basarak son mangaları kullanılabilir hale getirin + Sağ kenara dokunulduğunda veya sağ tuşa basıldığında her zaman bir sonraki sayfaya geçilir + Kaynak devre dışı + İçerik ön yüklemesi + Geçerli olarak işaretle + Dil + Günlükleri paylaş + Günlük kaydını etkinleştir + Hata ayıklama amacıyla bazı eylemleri kaydedin + Şüpheli içeriği göster + Hizmetler + Okuma ilerlemesini izlemek için manga ayrıntıları ekranında Menü → İzle\'yi seçin. + burada hiçbir şey yok + Dinamik + renk vurgusu + Izgara görünümünde göster + Mamimi + Kanade + UserAgent başlığı + Uygulamanın beta sürümleri için güncellemeler öner + Kararsız güncellemelere izin ver + İndirme başladı + Miku + Asuka + Mion + Rikka + Sakura + Bu değişiklikleri uygulamak için lütfen uygulamayı yeniden başlatın + Benzerini bul + Çeviriler + WebView kullanılamıyor: WebView sağlayıcısının kurulu olup olmadığını kontrol edin + Etkinleştir + Hayır teşekkürler + İnternet geçmişini temizle + Eşitleme seçenekleri + Sunucu adresi + "Şirket içinde barındırılan bir eşitleme sunucusu veya varsayılan bir sunucu kullanabilirsiniz. Ne yaptığınızdan emin değilseniz bunu değiştirmeyin." + Yansıtmalar varsa, hatalarda uzak kaynaklar için etki alanlarını otomatik olarak değiştir + Mobil ağa geçerken indirmeyi durdur + Bitirilenleri kaldır + Hepsini iptal et + Sadece Wi-Fi ile indir + Anladım + Yeniden sıralamak için bir öğeye dokunun ve basılı tutun + Bir veya daha fazla .cbz veya .zip dosyası seçebilirsiniz, her dosya ayrı bir manga olarak tanınacaktır. + Arşivler veya resimler içeren bir dizin seçebilirsiniz. Her arşiv (veya alt dizin) bir bölüm olarak tanınacaktır. + Hız + Kullanıcı verilerinin önceden oluşturulmuş bir yedeğini içe aktarın + Rafta Göster + Mevcut bir hesapta oturum açabilir veya yeni bir hesap oluşturabilirsiniz. + SSL hatalarını görmezden gel + Durdur + Devam et + Durduruldu + Öneri:%s + Bazen manga öneri bildirimlerilerini göster + Daha fazla + Tüm aktif indirmeler iptal edilecek, kısmen indirilen veriler kaybolacak + İndirme geçmişin tamamen silinecek + Hiçbir indirmeniz yok + İndirmeler devam ettirildi + İndirmeler durduruldu + İndirmeler silindi + Aynayı otomatik olarak seç + İndirmeler iptal edildi + Kişiselleştirilmiş manga önerileri almak istiyor musunuz\? + Adres + Tür + %1$s (%2$s) + Menü + Proxy + Geçersiz değer + Geçersiz port numarası + Renkleri ters çevir + Görüntü optimizasyon proxy\'si + Şifre + Doğrulama (isteğe bağlı) + İndirildi + Trafik kullanımını azaltmak ve mümkünse resim yüklemeyi hızlandırmak için wsrv.nl hizmetini kullanın + Kullanıcı adı + \ No newline at end of file From c14b2ceeff5457fcc5fd570d1fc799092af622f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D0=B0=D1=80=20=D0=A0=D0=B0=D0=B7=D0=B8?= =?UTF-8?q?=D0=BD?= Date: Mon, 5 Jun 2023 11:53:40 +0200 Subject: [PATCH 49/94] Translated using Weblate (Ukrainian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (431 of 431 strings) Translated using Weblate (Russian) Currently translated at 100.0% (431 of 431 strings) Translated using Weblate (Belarusian) Currently translated at 100.0% (431 of 431 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Russian) Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Belarusian) Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Polish) Currently translated at 100.0% (421 of 421 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (421 of 421 strings) Translated using Weblate (Russian) Currently translated at 100.0% (421 of 421 strings) Translated using Weblate (French) Currently translated at 100.0% (421 of 421 strings) Co-authored-by: Макар Разин Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/ Translation: Kotatsu/Strings --- app/src/main/res/values-be/strings.xml | 10 + app/src/main/res/values-fr/strings.xml | 5 + app/src/main/res/values-pl/strings.xml | 768 ++++++++++++++----------- app/src/main/res/values-ru/strings.xml | 15 + app/src/main/res/values-uk/strings.xml | 15 + 5 files changed, 463 insertions(+), 350 deletions(-) diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index 8c17722f5..dec1c2e78 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -417,4 +417,14 @@ Порт Проксі Ачысціць сеткавы кэш + %1$s (%2$s) + Няправільнае значэнне + Спампавана + Проксі для аптымізацыі малюнкаў + Імя карыстальніка + Няправільны нумар порта + Аўтарызацыя (неабавязкова) + Выкарыстоўвайце службу wsrv.nl, каб паменшыць выкарыстанне трафіку і паскорыць загрузку малюнкаў, калі гэта магчыма + Пароль + Інвертаваць колеры \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 758eedf94..cd7193ee6 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -412,4 +412,9 @@ Voulez-vous recevoir des suggestions de mangas personnalisées \? WebView non disponible : vérifier si le fournisseur WebView est installé Traductions + Effacer le cache réseau + Taper + Adresse + Port + Proxy \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index c42b524c2..9dc982b98 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1,352 +1,420 @@ - Ulubione - Historia - Napotkano błąd - Szczegółowy - Rozdziały - Lista - Lista szczegółowa - Siatka - Tryb listy - Ustawienia - Ładowanie… - Rozdział %1$d z %2$d - Zamknij - Wyczyść historię - Dodaj - Zapisz - Udostępnij - Szukaj - Szukaj mang - Pobieranie… - Pobrano - Pobrane - Nazwa - Popularność - Najnowsze - Ocena - Filtry - Jasny - Ciemny - Strony - Wyczyść - Usuń - Udostępnij zdjęcie - Usuń - Brak opisu - Tryb czytania - Błąd sieci - Obliczanie… - Spróbuj ponownie - Nic nie znaleziono - Brak historii - Czytaj - Brak ulubionych - Dodaj do ulubionych - Nowa kategoria - Stwórz skrót - Udostępnij %s - Przetwarzanie… - Zaktualizowane - Zapisz stronę - Zapisano - Wibracje - Biblioteka - Ostatnie - Tryb czarny - Przygotowywanie… - Plik nieznaleziony - Wczoraj - Dawno temu - Grupa - Dzisiaj - Zaloguj - Dalej - Potwierdź - Witaj - Skończone - W trakcie - Zezwól - Proponowane - Włącz propozycje - Włączone - Wyłączone - Nigdy - Zawsze - Znajdź rozdział - %1$s%% - Wygląd - Schowaj - Synchronizacja - Synchronizuj swoje dane - Nazwa - Edytuj - Wyloguj - Cofnij - Wyślij - Planowane - Czytane - Czytane ponownie - Skończone - Pokaż wszystkie - Wybierz zakres - Wyczyść całą historię - Ostatnie 2 godziny - Historia wyczyszczona - Zarządzaj - Losowe - Puste - Przeglądaj - Dostępne - Ustawienia - Źródło wyłączone - Kompaktowy - Błąd po stronie serwera (%1$d). Sprónuj ponownie później - Sieć niedostępna - Inne języki - Odrzuć - Jasność - Kontrast - Korekcja kolorów - Automatyczne przewijanie - Brak rozdziałów - Tryb incognito - Usunięto z ulubionych - Wykorzystana pamięć - Zapisane mangi - Brak zakładek - Możesz tworzyć zakładki w trakcie czytania mangi - Zakładki usunięte - Twoje ostatnio czytane mangi - Wyłącz wszystkie - Wyłącz optymalizację baterii - Autowykrywanie trybu czytania - Usunięte z historii - Dodano zakładkę - Usunięto zakładkę - Zakładki - Usuń zakładkę - Dodaj zakładkę - Brak ulubionych kategorii - Edytuj kategorię - Włącz powiadomienia - Wróć - Konto już istnieje - Anulowano - Zwolnienie pobierania - Brak rozdziałów w tej mandze - Różne języki - Tylko na Wi-Fi - Zawsze blokuj - Gatunki - Znajdź gatunek - Czytaj więcej - Rozwiąż - Wymagane CAPTCHA - Cichy - Dotknij aby spróbować ponownie - Teraz - Przywrócone - Dopasuj do szerokości - Dopasuj do wysokości - Dopasuj do środka - Nowa kategoria - Brak nowych aktualizacji - Sprawdź dostępność aktualizacji - Wersja %s - O aplikacji - Usuń - Jest tu dosyć pusto… - Ulubione kategorie - Powiadomienie LED - Nowe rozdziały - Pamięć wewnętrzna - Tutaj będą wyświetlane Twoje mangi - Znajdź materiały do czytania w zakładce „Przeglądaj” - W tym miejscu pojawią się powiadomienia o nowych rozdziałach z mang które czytasz - Strony w pamięci podręcznej - Animacja przewracania strony - Inne rzeczy w pamięci podręcznej - Otwórz w przeglądarce - Numerowane strony - Powiadomienia - Dźwięk powiadomień - Ustawienia powiadomień - Zewnętrzne źródła - Motyw - Systemowy - Historia i pamięć podręczna - Wyczyść pamięć podręczną stron - B|kB|MB|GB|TB - Wielkość siatki - Szukaj na %s - Usuń mangę - Dalej - Błąd - Wyczyszczone - Pamięć wewnętrzna - Pamięć zewnętrzna - Domena - Nowa wersja aplikacji jest dostępna - Ta manga ma %s. Zapisać wszystko? - Zapisz - Pobierz - Najpierw coś zapisz - Niedostępne - Zapisz - Wszystkie ulubione - Pusta kategoria - Czytaj później - Aktualizacje - Nowa wersja: %s - Wielkość: %s - Obróć ekran - Odśwież - Szukaj aktualizacji - Nie sprawdzaj - Wprowadź hasło - Złe hasło - Chroń aplikację - Pytaj o hasło przy starcie Kotatsu - Wprowadź ponownie hasło - Zużywa mniej prądu na ekranach AMOLED - Kopia zapasowa i przywracanie - Utwórz kopię zapasową danych - Przywróć z kopii zapasowej - 18+ - %1$d na %2$d włączone - Standardowy - Webtoon - Ustawienia czytnika - Zmiana strony - Przyciski głośności - Dotknięcie krawędzi - Wyczyszczone - Tryb skalowania - Wyczyść ciasteczka - Wszystkie ciasteczka wyczyszczone - Przetłumacz tą aplikację - Tłumaczenie - Dostępne źródła - Tylko gesty - Brak dostępnej pamięci - Inny - Wyniki wyszukiwania - Wszystkie dane zostały przywrócone - Dane zostały przywrócone, ale z błędami - Od tyłu - Domyślny - Polityka zrzutów ekranu - Wyklucz gatunki - Określ gatunki, których nie chcesz widzieć w sugestiach - Zalogowano jako %s - Wybierz języki, w których chcesz czytać mangi. Możesz zmienić to później w ustawieniach. - Zgłoś - Usuwanie danych - Nieważna domena - Zmień kolejność - Potwierdzenie wyjścia - %s - %s - Rozdz. %1$d/%2$d Str. %3$d/%4$d - Włącz Wi-Fi lub sieć komórkową, aby czytać mangę online - Importuj - Wybierz plik ZIP lub CBZ. - Wyczyść historię wyszukiwania - Ta operacja nie jest obsługiwana - Tryb sortowania - Treści - Nie można załadować listy gatunków - Wstrzymane - Porzucone - Użyj odcisku palca, jeśli jest dostępny - Mangi z Twoich ulubionych - Pokaż wskaźniki postępu czytania - Pokaż procent przeczytania w historii i ulubionych - Manga oznaczona jako NSFW nigdy nie zostanie dodana do historii, a Twoje postępy nie zostaną zapisane - DNS przez HTTPS - Tryb domyślny - Trwale wyczyścić całą historię czytania? - „%s” usunięte z pamięci lokalnej - Wyczyść tablicę aktualizacji - Tablica - Usunąć trwale „%s” z urządzenia? - Wyczyść pamięć podręczną miniatur - Spróbuj przeformułować zapytanie. - To co czytasz będzie wyświetlane tutaj - Znajdź to, co warto przeczytać, w menu bocznym. - Zapisz ze źródeł online lub zaimportuj pliki. - Folder pobranych - Aktualizacja tablicy rozpocznie się wkrótce - Niezgodne hasła - Od prawej do lewej - Trzymaj na starcie - Możesz utworzyć kopię zapasową swojej historii i ulubionych oraz przywrócić ją - Wybrana konfiguracja zostanie zapamiętana dla tej mangi - Wyczyść tablicę - Wyczyścić trwale całą historię aktualizacji? - Szukanie nowych rozdziałów - Zaloguj się, aby wyświetlić tę zawartość - Domyślnie: %s - Wprowadź hasło, aby uruchomić aplikację - Hasło musi mieć co najmniej 4 znaki - Trwale usunąć wszystkie ostatnie zapytania wyszukiwania? - Zapisano kopię zapasową - Systemy niektórych urządzeń inaczej się zachowują. Może to zakłócać wykonywanie zadań w tle. - W kolejce - Pobierz lub przeczytaj ten brakujący rozdział online. - Brak rozdziału - Uprawniony - Logowanie na %s nie jest obsługiwane - Zostaniesz wylogowany ze wszystkich źródeł - Wyklucz mangi NSFW z historii - Wykorzystane źródła - Zablokuj na NSFW - Proponuj mangi na podstawie Twoich preferencji - Wszystkie dane są analizowane lokalnie na tym urządzeniu. Twoje dane osobowe nie są przekazywane do żadnych usług - Zacznij czytać mangę, a otrzymasz spersonalizowane sugestie - Nie proponuj mang NSFW - Zresetuj filtr - Ładuj wstępnie strony - Aktualizowanie sugestii - Trwale usunąć wybrane elementy z urządzenia? - Usuwanie zakończone - Pomaga uniknąć blokowania Twojego adresu IP - Przetwarzanie zapisanej mangi - Rozdziały zostaną usunięte w tle. Może to zająć trochę czasu - Wpisz swój adres e-mail, aby kontynuować - Dostępne są nowe źródła mang - Sprawdzaj dostępność nowych rozdziałów i informuj o nich - Będziesz otrzymywać powiadomienia o aktualizacjach mang, które czytasz - Nie będziesz otrzymywać powiadomień, ale nowe rozdziały będą podświetlane na listach - Śledzenie - Automatycznie wykryj, czy manga to webtoon - Pomaga w sprawdzaniu aktualizacji w tle - Coś poszło nie tak. Zgłoś błąd programistom, aby pomóc nam go naprawić. - Może pomóc w przypadku niektórych problemów. Wszystkie autoryzacje zostaną unieważnione - Brak źródeł mang - Włącz źródła mang do czytania mang online - Czy na pewno chcesz usunąć wybrane ulubione kategorie? Wszystkie w nich mangi zostaną usunięte i nie będzie można tego cofnąć. - Naciśnij ponownie Wstecz, aby wyjść - Naciśnij dwukrotnie przycisk Wstecz, aby wyjść z aplikacji - Treść nie została znaleziona lub została usunięta - Pokaż pasek informacji w czytniku - Archiwum komiksów - Folder z obrazami - Importowanie mangi - Importowanie zakończone - Możesz usunąć oryginalny plik z pamięci, aby zaoszczędzić miejsce - Import rozpocznie się wkrótce - Wybrane ustawienia kolorów zostaną zapamiętane dla tej mangi - Pokaż ostatnie skróty do mang - Pokaż ostatnie mangi po długim naciśnięciu ikony aplikacji - Stuknięcie w prawą krawędź lub naciśnięcie prawego klawisza zawsze powoduje przejście do następnej strony - Ergonomiczne sterowanie czytnikiem - Zapisać czy odrzucić niezapisane zmiany? - Brak miejsca w urządzeniu - Pokaż suwak przełączania stron - Powiększanie webtoon - Wyczyść też informacje o nowych rozdziałach - Resetuj - Szczegóły błędu:<br><tt>%1$s</tt><br><br>1. Spróbuj <a href=%2$s>otworzyć mangę w przeglądarce internetowej</a> aby upewnić się, że jest dostępna w źródle<br>2. Jeśli jest dostępna, wyślij raport o błędzie do programistów. - + Ulubione + Historia + Napotkano błąd + Szczegółowy + Rozdziały + Lista + Lista szczegółowa + Siatka + Tryb listy + Ustawienia + Ładowanie… + Rozdział %1$d z %2$d + Zamknij + Wyczyść historię + Dodaj + Zapisz + Udostępnij + Szukaj + Szukaj mang + Pobieranie… + Pobrano + Pobrane + Nazwa + Popularność + Najnowsze + Ocena + Filtry + Jasny + Ciemny + Strony + Wyczyść + Usuń + Udostępnij zdjęcie + Usuń + Brak opisu + Tryb czytania + Błąd sieci + Obliczanie… + Spróbuj ponownie + Nic nie znaleziono + Brak historii + Czytaj + Brak ulubionych + Dodaj do ulubionych + Nowa kategoria + Stwórz skrót… + Udostępnij %s + Przetwarzanie… + Zaktualizowane + Zapisz stronę + Zapisano + Wibracje + Biblioteka + Ostatnie + Tryb czarny + Przygotowywanie… + Plik nieznaleziony + Wczoraj + Dawno temu + Grupa + Dzisiaj + Zaloguj + Dalej + Potwierdź + Witaj + Skończone + W trakcie + Zezwól + Proponowane + Włącz propozycje + Włączone + Wyłączone + Nigdy + Zawsze + Znajdź rozdział + %1$s%% + Wygląd + Schowaj + Synchronizacja + Synchronizuj swoje dane + Nazwa + Edytuj + Wyloguj + Cofnij + Wyślij + Planowane + Czytane + Czytane ponownie + Skończone + Pokaż wszystkie + Wybierz zakres + Wyczyść całą historię + Ostatnie 2 godziny + Historia wyczyszczona + Zarządzaj + Losowe + Puste + Przeglądaj + Dostępne + Ustawienia + Źródło wyłączone + Kompaktowy + Błąd po stronie serwera (%1$d). Sprónuj ponownie później + Sieć niedostępna + Inne języki + Odrzuć + Jasność + Kontrast + Korekcja kolorów + Automatyczne przewijanie + Brak rozdziałów + Tryb incognito + Usunięto z ulubionych + Wykorzystana pamięć + Zapisane mangi + Brak zakładek + Możesz tworzyć zakładki w trakcie czytania mangi + Zakładki usunięte + Twoje ostatnio czytane mangi + Wyłącz wszystkie + Wyłącz optymalizację baterii + Autowykrywanie trybu czytania + Usunięte z historii + Dodano zakładkę + Usunięto zakładkę + Zakładki + Usuń zakładkę + Dodaj zakładkę + Brak ulubionych kategorii + Edytuj kategorię + Włącz powiadomienia + Wróć + Konto już istnieje + Anulowano + Zwolnienie pobierania + Brak rozdziałów w tej mandze + Różne języki + Tylko na Wi-Fi + Zawsze blokuj + Gatunki + Znajdź gatunek + Czytaj więcej + Rozwiąż + Wymagane CAPTCHA + Cichy + Dotknij aby spróbować ponownie + Teraz + Przywrócone + Dopasuj do szerokości + Dopasuj do wysokości + Dopasuj do środka + Nowa kategoria + Brak nowych aktualizacji + Sprawdź dostępność aktualizacji + Wersja %s + O aplikacji + Usuń + Jest tu dosyć pusto… + Ulubione kategorie + Powiadomienie LED + Nowe rozdziały + Pamięć wewnętrzna + Tutaj będą wyświetlane Twoje mangi + Znajdź materiały do czytania w zakładce „Przeglądaj” + W tym miejscu pojawią się powiadomienia o nowych rozdziałach z mang które czytasz + Strony w pamięci podręcznej + Animacja przewracania strony + Inne rzeczy w pamięci podręcznej + Otwórz w przeglądarce + Numerowane strony + Powiadomienia + Dźwięk powiadomień + Ustawienia powiadomień + Zewnętrzne źródła + Motyw + Systemowy + Historia i pamięć podręczna + Wyczyść pamięć podręczną stron + B|kB|MB|GB|TB + Wielkość siatki + Szukaj na %s + Usuń mangę + Dalej + Błąd + Wyczyszczone + Pamięć wewnętrzna + Pamięć zewnętrzna + Domena + Nowa wersja aplikacji jest dostępna + Ta manga ma %s. Zapisać wszystko? + Zapisz + Pobierz + Najpierw coś zapisz + Niedostępne + Zapisz + Wszystkie ulubione + Pusta kategoria + Czytaj później + Aktualizacje + Nowa wersja: %s + Wielkość: %s + Obróć ekran + Odśwież + Szukaj aktualizacji + Nie sprawdzaj + Wprowadź hasło + Złe hasło + Chroń aplikację + Pytaj o hasło przy starcie Kotatsu + Wprowadź ponownie hasło + Zużywa mniej prądu na ekranach AMOLED + Kopia zapasowa i przywracanie + Utwórz kopię zapasową danych + Przywróć z kopii zapasowej + 18+ + %1$d na %2$d włączone + Standardowy + Webtoon + Ustawienia czytnika + Zmiana strony + Przyciski głośności + Dotknięcie krawędzi + Wyczyszczone + Tryb skalowania + Wyczyść ciasteczka + Wszystkie ciasteczka wyczyszczone + Przetłumacz tą aplikację + Tłumaczenie + Dostępne źródła + Tylko gesty + Brak dostępnej pamięci + Inny + Wyniki wyszukiwania + Wszystkie dane zostały przywrócone + Dane zostały przywrócone, ale z błędami + Od tyłu + Domyślny + Polityka zrzutów ekranu + Wyklucz gatunki + Określ gatunki, których nie chcesz widzieć w sugestiach + Zalogowano jako %s + Wybierz języki, w których chcesz czytać mangi. Możesz zmienić to później w ustawieniach. + Zgłoś + Usuwanie danych + Nieważna domena + Zmień kolejność + Potwierdzenie wyjścia + %s - %s + Rozdz. %1$d/%2$d Str. %3$d/%4$d + Włącz Wi-Fi lub sieć komórkową, aby czytać mangę online + Importuj + Wybierz plik ZIP lub CBZ. + Wyczyść historię wyszukiwania + Ta operacja nie jest obsługiwana + Tryb sortowania + Treści + Nie można załadować listy gatunków + Wstrzymane + Porzucone + Użyj odcisku palca, jeśli jest dostępny + Mangi z Twoich ulubionych + Pokaż wskaźniki postępu czytania + Pokaż procent przeczytania w historii i ulubionych + Manga oznaczona jako NSFW nigdy nie zostanie dodana do historii, a Twoje postępy nie zostaną zapisane + DNS przez HTTPS + Tryb domyślny + Trwale wyczyścić całą historię czytania? + „%s” usunięte z pamięci lokalnej + Wyczyść tablicę aktualizacji + Tablica + Usunąć trwale „%s” z urządzenia? + Wyczyść pamięć podręczną miniatur + Spróbuj przeformułować zapytanie. + To co czytasz będzie wyświetlane tutaj + Znajdź to, co warto przeczytać, w menu bocznym. + Zapisz ze źródeł online lub zaimportuj pliki. + Folder pobranych + Aktualizacja tablicy rozpocznie się wkrótce + Niezgodne hasła + Od prawej do lewej + Trzymaj na starcie + Możesz utworzyć kopię zapasową swojej historii i ulubionych oraz przywrócić ją + Wybrana konfiguracja zostanie zapamiętana dla tej mangi + Wyczyść tablicę + Wyczyścić trwale całą historię aktualizacji? + Szukanie nowych rozdziałów + Zaloguj się, aby wyświetlić tę zawartość + Domyślnie: %s + Wprowadź hasło, aby uruchomić aplikację + Hasło musi mieć co najmniej 4 znaki + Trwale usunąć wszystkie ostatnie zapytania wyszukiwania? + Zapisano kopię zapasową + Systemy niektórych urządzeń inaczej się zachowują. Może to zakłócać wykonywanie zadań w tle. + W kolejce + Pobierz lub przeczytaj ten brakujący rozdział online. + Brak rozdziału + Uprawniony + Logowanie na %s nie jest obsługiwane + Zostaniesz wylogowany ze wszystkich źródeł + Wyklucz mangi NSFW z historii + Wykorzystane źródła + Zablokuj na NSFW + Proponuj mangi na podstawie Twoich preferencji + Wszystkie dane są analizowane tylko lokalnie na tym urządzeniu i nigdy nie są nigdzie wysyłane. + Zacznij czytać mangę, a otrzymasz spersonalizowane sugestie + Nie proponuj mang NSFW + Zresetuj filtr + Ładuj wstępnie strony + Aktualizowanie sugestii + Trwale usunąć wybrane elementy z urządzenia? + Usuwanie zakończone + Pomaga uniknąć blokowania Twojego adresu IP + Przetwarzanie zapisanej mangi + Rozdziały zostaną usunięte w tle + Wpisz swój adres e-mail, aby kontynuować + Dostępne są nowe źródła mang + Sprawdzaj dostępność nowych rozdziałów i informuj o nich + Będziesz otrzymywać powiadomienia o aktualizacjach mang, które czytasz + Nie będziesz otrzymywać powiadomień, ale nowe rozdziały będą podświetlane na listach + Śledzenie + Automatycznie wykryj, czy manga to webtoon + Pomaga w sprawdzaniu aktualizacji w tle + Coś poszło nie tak. Zgłoś błąd programistom, aby pomóc nam go naprawić. + Może pomóc w przypadku niektórych problemów. Wszystkie autoryzacje zostaną unieważnione + Brak źródeł mang + Włącz źródła mang do czytania mang online + Czy na pewno chcesz usunąć wybrane ulubione kategorie\? +\nWszystkie w nich mangi zostaną usunięte i nie będzie można tego cofnąć. + Naciśnij ponownie Wstecz, aby wyjść + Naciśnij dwukrotnie przycisk Wstecz, aby wyjść z aplikacji + Treść nie została znaleziona lub została usunięta + Pokaż pasek informacji w czytniku + Archiwum komiksów + Folder z obrazami + Importowanie mangi + Importowanie zakończone + Możesz usunąć oryginalny plik z pamięci, aby zaoszczędzić miejsce + Import rozpocznie się wkrótce + Wybrane ustawienia kolorów zostaną zapamiętane dla tej mangi + Pokaż ostatnie skróty do mang + Pokaż ostatnie mangi po długim naciśnięciu ikony aplikacji + Stuknięcie w prawą krawędź lub naciśnięcie prawego klawisza zawsze powoduje przejście do następnej strony + Ergonomiczne sterowanie czytnikiem + Zapisać czy odrzucić niezapisane zmiany? + Brak miejsca w urządzeniu + Pokaż suwak przełączania stron + Powiększanie webtoon + Wyczyść też informacje o nowych rozdziałach + Resetuj + Szczegóły błędu:<br><tt>%1$s</tt><br><br>1. Spróbuj <a href=%2$s>otworzyć mangę w przeglądarce internetowej</a>, aby upewnić się, że jest dostępna w swoim źródle<br>2. Upewnij się, że używasz <a href=kotatsu://about>najnowszej wersji Kotatsu</a><br>3. Jeśli jest dostępny, wyślij raport o błędzie do programistów. + Mamimi + Kanade + Usługi + Tutaj nic nie ma + By śledzić postęp w czytaniu, wybierz Menu → Śledź na ekranie detali mangi. + Znajdź podobne + Nagłówek UserAgent + Tłumaczenia + Udostępnij dzienniki + Zapisz niektóre działania do celów debugowania + Zezwól na niestabilne altualizacje + Rozumiem + Uruchom ponownie aplikację by wprowadzić te zmiany + Prędkość + Stuknij i przytrzymaj element, aby zmienić jego kolejność + Możesz wybrać jeden lub więcej plików .cbz lub .zip, każdy plik zostanie rozpoznany jako osobna manga. + Możesz wybrać katalog z archiwami lub obrazami. Każde archiwum (lub podkatalog) zostanie rozpoznane jako rozdział. + Włączać + Wstępne ładowanie treści + Oznacz jako aktualne + Włącz logowanie + Pokaż podejrzane treści + Schemat kolorów + Pokaż w widoku siatki + Miku + Dynamiczne + Asuka + Rikka + Sakura + Mion + Ignoruj błędy SSL + Wybierz lustro automatycznie + Zaimportuj utworzoną wcześniej kopię zapasową danych użytkownika + Pokaż na półce + Automatycznie przełączaj domeny dla zdalnych źródeł w przypadku błędów, jeśli dostępne są kopie lustrzane + Pauza + Wznawiać + Wstrzymane + Anulować całość + Pobieraj tylko przez Wi-Fi + Zatrzymaj pobieranie po przełączeniu na sieć komórkową + Sugestia: %s + Czasami wyświetlaj powiadomienia z sugerowaną mangą + Więcej + Nie, dziękuję + Wszystkie aktywne pobrania zostaną anulowane, częściowo pobrane dane zostaną utracone + Usuwanie zakończone + Język + Zaproponuj aktualizacje do wersji beta aplikacji + Pobieranie rozpoczęte + Ustawienia synchronizacji + Adres serwera + Możesz użyć samoobsługowego serwera synchronizacji lub serwera domyślnego. Nie zmieniaj tego, jeśli nie jesteś pewien, co robisz. + Twoja historia pobrań zostanie trwale usunięta + Nie masz żadnych pobrań + Pobieranie zostało wstrzymane + Pobieranie zostało wznowione + Pobieranie zostało anulowane + Pliki do pobrania zostały usunięte + Czy chcesz otrzymywać spersonalizowane sugestie dotyczące mangi\? + WebView niedostępny: sprawdź, czy dostawca WebView jest zainstalowany + Wyczyść pamięć podręczną sieci + Typ + Adres + Port + Proxy + Możesz zalogować się na istniejące konto lub utworzyć nowe + \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 3ce28e5c0..8c4ba3aa2 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -412,4 +412,19 @@ Хотите ли Вы получать персонализированные рекомендации манги\? Переводы WebView недоступен: проверьте, установлен ли провайдер WebView + Очистить сетевой кеш + Адрес + Тип + Прокси + Порт + %1$s (%2$s) + Неверное значение + Неверный номер порта + Имя пользователя + Пароль + Авторизация (необязательна) + Скачано + Прокси для оптимизации изображений + Используйте службу wsrv.nl, чтобы уменьшить использование трафика и ускорить загрузку изображений, если это возможно + Инвертировать цвета \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 0304f772b..38574837e 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -412,4 +412,19 @@ Хочете отримувати персоналізовані пропозиції щодо манги\? WebView недоступний: перевірте, чи встановлено провайдер WebView Переклади + Очистити мережевий кеш + Порт + Проксі + Тип + Адреса + %1$s (%2$s) + Недійсне значення + Недійсний номер порту + Використовуйте службу wsrv.nl, щоб зменшити використання трафіку та прискорити завантаження зображень, якщо це можливо + Завантажено + Проксі для оптимізації зображень + Авторизація (необов\'язково) + Пароль + Ім\'я користувача + Інвертувати кольори \ No newline at end of file From 056ef5433d60102b3b3eb0460b199697ebb682cf Mon Sep 17 00:00:00 2001 From: Reza Almanda Date: Mon, 5 Jun 2023 11:53:40 +0200 Subject: [PATCH 50/94] Translated using Weblate (Indonesian) Currently translated at 100.0% (421 of 421 strings) Co-authored-by: Reza Almanda Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/ Translation: Kotatsu/Strings --- app/src/main/res/values-in/strings.xml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index bd3346c8a..7cda7bcce 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -1,6 +1,6 @@ - Lokal + Penyimpanan lokal Favorit Riwayat Terjadi kesalahan @@ -160,7 +160,7 @@ Selalu blokir Saran Aktifkan saran - Sarankan komik berdasarkan preferensi Anda + Sarankan manga berdasarkan preferensi Anda Semua data hanya dianalisis secara lokal pada perangkat ini dan tidak pernah dikirim ke mana pun. Mulai membaca komik dan Anda akan mendapatkan saran yang dipersonalisasi Jangan menyarankan komik NSFW @@ -296,7 +296,7 @@ Folder dengan gambar Anda bisa menghapus berkas asli dari penyimpanan untuk menghemat ruang Umpan - Detail kesalahan:<br><tt>%1$s</tt><br><br>1. Coba <a href=%2$s>buka komik di browser</a> untuk memastikan komik tersedia di sumbernya<br>2. Pastikan Anda menggunakan <a href=kotatsu://about>Kotatsu versi terbaru</a><br>3. Jika tersedia, kirim laporan kesalahan ke pengembang. + Rincian error:<tt>%1$s</tt><br><br>1. Coba <a href=%2$s>buka manga di peramban web</a> untuk memastikan manga tersebut tersedia di sumbernya</a>2. Pastikan Anda menggunakan <a href= >manga versi terbaru</a><br>3. Jika tersedia, kirimkan laporan kesalahan ke pengembang. Pastikan Anda menggunakan <a href=kotatsu://about>versi terbaru Kotatsu</a><br>3. Jika tersedia, kirimkan laporan kesalahan ke pengembang. Kecerahan Kontras Atur Ulang @@ -375,12 +375,12 @@ Zoom webtoon Berbagai bahasa Jaringan tidak tersedia - Mengerti + Oke Ketuk dan tahan item untuk menyusun ulang Anda dapat memilih satu atau beberapa file .cbz atau .zip, setiap file akan dikenali sebagai komik terpisah. Anda dapat memilih direktori yang berisi arsip atau gambar. Setiap arsip (atau subdirektori) akan dikenali sebagai sebuah bab. Kecepatan - Impor cadangan data pengguna yang dibuat sebelumnya + Impor cadangan data pengguna yang telah dibuat sebelumnya Tampilkan di Rak Anda dapat masuk ke akun yang sudah ada atau membuat akun baru Temukan serupa @@ -401,7 +401,7 @@ Batalkan semua Berhenti mengunduh saat beralih ke jaringan seluler Saran: %s - Terkadang menampilkan notifikasi dengan komik yang disarankan + Terkadang menampilkan notifikasi dengan manga yang disarankan Lebih Semua pengunduhan yang aktif akan dibatalkan, data yang sudah terunduh sebagian akan hilang Riwayat unduhan Anda akan dihapus secara permanen @@ -410,4 +410,11 @@ Unduhan telah dijeda Unduhan telah dihapus Apakah Anda ingin menerima saran manga yang dipersonalisasi\? + Terjemahan + WebView tidak tersedia: periksa apakah penyedia WebView telah diinstal + Hapus cache jaringan + Tipe + Alamat + Port + Proksi \ No newline at end of file From 00307062261a455d66b305068bfec5ddd775bed1 Mon Sep 17 00:00:00 2001 From: Clxff H3r4ld0 <123844876+clxf12@users.noreply.github.com> Date: Mon, 5 Jun 2023 11:53:41 +0200 Subject: [PATCH 51/94] Translated using Weblate (Indonesian) Currently translated at 100.0% (430 of 430 strings) Translated using Weblate (Indonesian) Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Indonesian) Currently translated at 100.0% (422 of 422 strings) Co-authored-by: Clxff H3r4ld0 <123844876+clxf12@users.noreply.github.com> Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/ Translation: Kotatsu/Strings --- app/src/main/res/values-in/strings.xml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 7cda7bcce..cd8f8db8a 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -148,7 +148,7 @@ Anda akan keluar dari semua sumber Genre Selesai - Berlanjut + Sedang berlangsung Standar Kecualikan komik NSFW dari riwayat Nomor halaman @@ -187,7 +187,7 @@ Hapus yang dipilih dari perangkat secara permanen\? Selesai menghapus Perlambat unduhan - Pembaruan saran + Memperbarui saran Membantu menghidari pemblokiran alamat IP Anda Bab akan dihapus di latar belakang Sembunyikan @@ -216,7 +216,7 @@ Kategori favorit Hapus Bersihkan umpan pembaruan - Kanan ke kiri + Kanan-ke-kiri Putar layar Pembaruan umpan akan dimulai Masukkan kata sandi @@ -248,8 +248,8 @@ Pas tinggi Pas lebar Balik - Antri - Diotorisasi + Mengantri + Resmi Simpan dari sumber daring atau berkas impor. Komik Anda akan ditampilkan di sini Cari apa untuk dibaca di bagian «Jelajah» @@ -354,7 +354,7 @@ Tampilkan indikator kemajuan membaca Tampilkan persentase baca dalam riwayat dan favorit Bahasa - Cobalah untuk merubah kueri. + Cobalah untuk memformulasi ulang kueri. Tetap di awal Bab. %1$d/%2$d Hal. %3$d/%4$d Aktifkan pencatatan @@ -417,4 +417,13 @@ Alamat Port Proksi + Nilai tidak valid + %1$s (%2$s) + Gunakan layanan wsrv.nl untuk mengurangi penggunaan lalu lintas dan mempercepat pemuatan gambar jika memungkinkan + Proksi pengoptimalan gambar + NamaUser + Diunduh + Balikkan warna + Kata sandi + Otorisasi (opsional) \ No newline at end of file From 50e67daea4f6174ad4e2ecb797e68e9a3121056f Mon Sep 17 00:00:00 2001 From: wr131 Date: Mon, 5 Jun 2023 11:53:41 +0200 Subject: [PATCH 52/94] Translated using Weblate (Chinese (Traditional)) Currently translated at 23.4% (99 of 422 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 99.2% (419 of 422 strings) Co-authored-by: wr131 Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hant/ Translation: Kotatsu/Strings --- app/src/main/res/values-zh-rCN/strings.xml | 7 +- app/src/main/res/values-zh-rTW/strings.xml | 191 +++++++++++---------- 2 files changed, 108 insertions(+), 90 deletions(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 5b20c9e2a..6ca5165d3 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -407,9 +407,14 @@ 下载被取消 你想要接收个人漫画推荐吗? 推荐:%s - 偶尔对建议的漫画显示通知 + 偶尔显示建议漫画通知 更多 所有进行中的下载都将被取消,未下载完成的数据将丢失 你的下载历史将会永久删除 你可以登陆一个已有账号或创建新账号 + 地址 + 清除网络缓存 + 代理 + 类型 + 无效值 \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 9d6ec4c85..830fe30b2 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1,91 +1,104 @@ - 你将不会收到通知,但新的章节将在列表中突出显示 - 计算… - 再试一次 - 尚无历史记录 - 不支持这种操作 - 在 \"探索 \"部分找到要读的内容 - 从在线来源保存或导入文件。 - 你所读的内容将在这里显示 - 在侧面菜单中找到要读的内容。 - 你的漫画将显示在这里 - 这里有点空… - 饲料更新将很快开始 - 所选择的配置将因这部漫画而被记住 - 数据被恢复了,但有错误 - 在AMOLED屏幕上使用更少的电力 - 登录后可查看此内容 - 永久地删除所有最近的搜索查询? - 永久地清除所有的更新历史? - 你将从所有来源中注销 - 從歷史中排除NSFW漫畫 - 开始阅读漫画,你会得到个性化的建议 - 根据你的喜好推荐漫画 - 指定您不希望在建议中看到的体裁 - 从设备中永久删除选定的项目? - 无法加载流派列表 - 章节将在后台被删除。这可能需要一些时间 - 检查新的章节并通知有关情况 - 有助于避免阻断你的IP地址 - 输入你的电子邮件以继续 - 有了新的漫画来源 - 自动检测漫画是否为网络漫画 - 在历史和收藏夹中显示阅读百分比 - 再次按 \"返回 \"键退出 - 本地存储 - 轻敲右边缘或按右键总是切换到下一页 - 你有未保存的修改,你想保存还是丢弃它们? - 您可以從儲存中刪除原始檔案以節省空間 - 最爱 - 章节 - 列表 - 栅格 - 设置 - 没有发现 - 选择你想看的漫画的语言。你可以在以后的设置中改变它。 - 可以在出现一些问题时提供帮助。所有授权将被视为无效 - 历史 - 发生了一个错误 - 无法连接到互联网 - 详情 - 第%1$d 。%2$d - 详细列表 - 列表模式 - 远程资源 - 正在加载… - 关闭 - 清除历史 - 所有的数据都在这个设备上进行本地分析。您的个人数据不会被转移到任何服务机构。 - 标记为NSFW的漫画将永远不会被添加到历史中,你的进度也不会被保存 - 你可以创建你的历史和收藏的备份并恢复它 - 出了点问题。请向开发人员提交一份错误报告,以帮助我们修复它。 - 所选择的颜色设置将被铭记在这部漫画中 - 要么选择ZIP或CBZ文件。 - 你可以在阅读漫画时创建书签 - 你会收到你正在阅读的漫画的更新通知 - 一些设备有不同的系统行为,这可能会破坏后台任务。 - 输入密码以启动应用程序 - 下载或在线阅读这缺失的章节。 - 在启动Kotatsu时要求输入密码 - 这部漫画中没有章节 - 你正在阅读的新章节显示在这里 - 通过长按应用程序图标来提供最近的漫画 - 这部漫画有%s 。全部保存? - 新版本的应用程序已经推出 - 密码必须是4个字符或以上 - 不支持在%s 上登录 - \"%s\" 从本地存储中删除 - 按两次 \"返回 \"键,退出应用程序 - 启用漫画来源,在线阅读漫画 - 永久清除所有阅读历史? - 从设备中永久删除 \"%s\"? - 尝试重新表述查询。 - 帮助进行背景更新检查 - 请勿推荐NSFW漫画 - 新类别 - 阅读 - 暂时没有喜欢的人 - 最喜欢这个 - 添加 - + 你将不会收到通知,但新的章节将在列表中突出显示 + 计算… + 再试一次 + 尚无历史记录 + 不支持这种操作 + 在 \"探索 \"部分找到要读的内容 + 从在线来源保存或导入文件。 + 你所读的内容将在这里显示 + 在侧面菜单中找到要读的内容。 + 你的漫画将显示在这里 + 这里有点空… + 饲料更新将很快开始 + 所选择的配置将因这部漫画而被记住 + 数据被恢复了,但有错误 + 在AMOLED屏幕上使用更少的电力 + 登录后可查看此内容 + 永久地删除所有最近的搜索查询? + 永久地清除所有的更新历史? + 你将从所有来源中注销 + 從歷史中排除NSFW漫畫 + 开始阅读漫画,你会得到个性化的建议 + 根据你的喜好推荐漫画 + 指定您不希望在建议中看到的体裁 + 从设备中永久删除选定的项目? + 无法加载流派列表 + 章节将在后台被删除。这可能需要一些时间 + 检查新的章节并通知有关情况 + 有助于避免阻断你的IP地址 + 输入你的电子邮件以继续 + 有了新的漫画来源 + 自动检测漫画是否为网络漫画 + 在历史和收藏夹中显示阅读百分比 + 再次按 \"返回 \"键退出 + 本地存储 + 轻敲右边缘或按右键总是切换到下一页 + 你有未保存的修改,你想保存还是丢弃它们? + 您可以從儲存中刪除原始檔案以節省空間 + 最爱 + 章节 + 列表 + 栅格 + 设置 + 没有发现 + 选择你想看的漫画的语言。你可以在以后的设置中改变它。 + 可以在出现一些问题时提供帮助。所有授权将被视为无效 + 历史 + 发生了一个错误 + 无法连接到互联网 + 详情 + 第%1$d 。%2$d + 详细列表 + 列表模式 + 远程资源 + 正在加载… + 关闭 + 清除历史 + 所有的数据都在这个设备上进行本地分析。您的个人数据不会被转移到任何服务机构。 + 标记为NSFW的漫画将永远不会被添加到历史中,你的进度也不会被保存 + 你可以创建你的历史和收藏的备份并恢复它 + 出了点问题。请向开发人员提交一份错误报告,以帮助我们修复它。 + 所选择的颜色设置将被铭记在这部漫画中 + 要么选择ZIP或CBZ文件。 + 你可以在阅读漫画时创建书签 + 你会收到你正在阅读的漫画的更新通知 + 一些设备有不同的系统行为,这可能会破坏后台任务。 + 输入密码以启动应用程序 + 下载或在线阅读这缺失的章节。 + 在启动Kotatsu时要求输入密码 + 这部漫画中没有章节 + 你正在阅读的新章节显示在这里 + 通过长按应用程序图标来提供最近的漫画 + 这部漫画有%s 。全部保存? + 新版本的应用程序已经推出 + 密码必须是4个字符或以上 + 不支持在%s 上登录 + \"%s\" 从本地存储中删除 + 按两次 \"返回 \"键,退出应用程序 + 启用漫画来源,在线阅读漫画 + 永久清除所有阅读历史? + 从设备中永久删除 \"%s\"? + 尝试重新表述查询。 + 帮助进行背景更新检查 + 请勿推荐NSFW漫画 + 新类别 + 阅读 + 暂时没有喜欢的人 + 最喜欢这个 + 添加 + 存儲 + 分享 %s + 搜尋 + 下載中…… + 已下載 + 過濾器 + 主題 + 淺色 + 清除 + 刪除 + 分享圖片 + 刪除 + 清除頁面快取 + \ No newline at end of file From 61a98f54b98cc751d88b10738eb643dd98d5a8b1 Mon Sep 17 00:00:00 2001 From: FateXBlood Date: Mon, 5 Jun 2023 11:53:42 +0200 Subject: [PATCH 53/94] Translated using Weblate (Nepali) Currently translated at 34.1% (144 of 422 strings) Co-authored-by: FateXBlood Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ne/ Translation: Kotatsu/Strings --- app/src/main/res/values-ne/strings.xml | 193 ++++++++++++++++++------- 1 file changed, 141 insertions(+), 52 deletions(-) diff --git a/app/src/main/res/values-ne/strings.xml b/app/src/main/res/values-ne/strings.xml index 9d72ad6df..446981da9 100644 --- a/app/src/main/res/values-ne/strings.xml +++ b/app/src/main/res/values-ne/strings.xml @@ -1,53 +1,142 @@ - - डाउनलोड गर्दै… - डाउनलोड गरेको - फिल्टर - अँध्यारो - खाली गर्नुहोस् - पृष्ठहरू - एउटा त्रुटि भयो - सूची मोड - सूची - पुनः प्रयास गर्नुहोस् - केही पनि फेला परेन - पढ्नुहोस् - लोकल भण्डारण - इतिहास - नेटवर्क त्रुटि - अध्यायहरू - सेटिङहरू - रिमोट स्रोतहरू - लोड हुँदै… - इतिहास खाली गर्नुहोस् - अहिले कुनै मनपर्ने छैन - मनपर्ने मा राख्नुहोस् - नयाँ वर्ग - %s साझा गर्नुहोस् - खोज्नुहोस् - माङ्गा खोज्नुहोस् - प्रक्रिया गर्दैछ… - डाउनलोडहरू - नाम - अपडेट गरियो - नवीनतम - क्रमबद्ध क्रम - थीम - उज्यालो - सिस्टम पालना गर्नुहोस् - कम्प्युटिङ… - मनपर्नेहरू - विवरणहरू - विस्तृत सूची - ग्रिड - %2$d को अध्याय %1$d - बन्द गर्नुहोस् - अहिलेसम्म इतिहास छैन - थप्नुहोस् - बचत गर्नुहोस् - साझा गर्नुहोस् - सर्टकट सिर्जना गर्नुहोस्… - लोकप्रिय - मूल्याङ्कन - नयाँ अध्यायहरू - + + डाउनलोड गर्दै… + डाउनलोड गरेको + फिल्टर + अँध्यारो + खाली गर्नुहोस् + पृष्ठहरू + एउटा त्रुटि भयो + सूची मोड + सूची + पुनः प्रयास गर्नुहोस् + केही पनि फेला परेन + पढ्नुहोस् + लोकल भण्डारण + इतिहास + नेटवर्क त्रुटि + अध्यायहरू + सेटिङहरू + माङ्गा स्रोतहरू + लोड हुँदै… + इतिहास खाली गर्नुहोस् + अहिले कुनै मनपर्ने छैन + मनपर्ने मा राख्नुहोस् + नयाँ वर्ग + %s साझा गर्नुहोस् + खोज्नुहोस् + माङ्गा खोज्नुहोस् + प्रक्रिया गर्दैछ… + डाउनलोडहरू + नाम + अपडेट गरिएको + नवीनतम + क्रमबद्ध क्रम + थीम + उज्यालो + सिस्टम पालना गर्नुहोस् + कम्प्युटिङ… + मनपर्नेहरू + विवरणहरू + विस्तृत सूची + ग्रिड + %2$d को अध्याय %1$d + बन्द गर्नुहोस् + अहिलेसम्म इतिहास छैन + थप्नुहोस् + बचत गर्नुहोस् + साझा गर्नुहोस् + सर्टकट सिर्जना गर्नुहोस्… + लोकप्रिय + मूल्याङ्कन + नयाँ अध्यायहरू + सबै पढेको इतिहास स्थायी रूपमा खाली गर्ने हो\? + हटाउनुहोस् + लोकल भण्डारणबाट %s हटाइयो + सेभ गरियो + पृष्ठ सेभ गर्नुहोस् + छवि साझा गर्नुहोस् + आयात गर्नुहोस् + स्ट्यानडर्ड + वेबटून + पढ्ने मोड + ग्रिड साइज + यन्त्रबाट %s स्थायी रूपमा हटाउने हो\? + रिडर सेटिङहरू + %s मा खोज्नुहोस् + माङ्गा हटाउनुहोस् + पृष्ठ स्विच गर्नुहोस् + किनारा ट्यापहरू + भोल्युम बटन + जारी राख्नुहोस् + त्रुटि + खाली गरियो + जेस्चर मात्र + थम्बनेल क्यास खाली गर्नुहोस् + खोज इतिहास खाली गर्नुहोस् + डोमेन + यो माङ्गामा %s छ। यो सबै सेभ गर्ने\? + आन्तरिक भण्डारण + एपको नयाँ संस्करण उपलब्ध छ + बाह्य भण्डारण + वेब ब्राउजरमा खोल्नुहोस् + डाउनलोड + सूचना सेटिङ + LED सूचक + भाईब्रेशन + मनपर्ने वर्गहरू + हटाउनुहोस् + यहाँ अलि खाली जस्तो छ… + सोधपुछ सुधार गर्ने प्रयास गर्नुहोस्। + तपाईँले पढेको कुरा यहाँ देखाइनेछ + साइड मेनुमा के पढ्ने फेला पार्नुहोस्। + पृष्ठ एनिमेसन + डाउनलोडका लागि फोल्डर + हालैका + उपलब्ध छैन + तपाईंले पढिरहनु भएको माङ्गाको नयाँ अध्यायहरू यहाँ देखाइएको छ + खोज परिणामहरू + अपडेट फिड खाली गर्नुहोस् + स्क्रिन घुमाउनुहोस् + अपडेट + पासवर्डहरू म्याच गरेनन् + बारेमा + संस्करण %s + यो अपरेशन समर्थित छैन + कुनै विवरण छैन + इतिहास र क्यास + पृष्ठ क्यास खाली गर्नुहोस् + सूचना आवाज + पहिले केही सेभ गर्नुहोस् + यसलाई अनलाइन स्रोतहरूबाट सेभ गर्नुहोस् वा फाइलहरू आयात गर्नुहोस्। + खाली गरियो + एप सुरक्षित गर्नुहोस् + Kotatsu सुरु गर्दा पासवर्ड माग्नुहोस् + पासवर्ड दोहोर्याउनुहोस् + हटाउनुहोस् + या त ZIP वा CBZ फाइल छान्नुहोस्। + B|kB|MB|GB|TB + सेभ + सूचनाहरू + %2$d को %1$d अन + तपाईंको माङ्गा यहाँ देखाउनेछ + «अन्वेषण» भागमा के पढ्ने फेला पार्नुहोस् + दराज + भण्डारण उपलब्ध छैन + अन्य भण्डारण + सकियो + सबै मनपर्नेहरू + खाली वर्ग + पछि पढ्ने + अपडेटहरू + नयाँ संस्करण: %s + साइज: %s + फिड अपडेट चाँडै सुरु हुनेछ + अपडेटहरू खोज्नुहोस् + जाँच नगर्नुहोस् + गलत पासवर्ड + अपडेटका लागि जाँच गर्नुहोस् + कुनै अपडेट उपलब्ध छैन + अन्वेषण + पासवर्ड एन्टर गर्नुहोस् + \ No newline at end of file From f11e964f0b2cbeba43651a5b8a1c7a7a8c1106cc Mon Sep 17 00:00:00 2001 From: frablock Date: Mon, 5 Jun 2023 11:53:42 +0200 Subject: [PATCH 54/94] Translated using Weblate (French) Currently translated at 100.0% (7 of 7 strings) Translated using Weblate (French) Currently translated at 100.0% (430 of 430 strings) Co-authored-by: frablock Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/fr/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/ Translation: Kotatsu/Strings Translation: Kotatsu/plurals --- app/src/main/res/values-fr/plurals.xml | 65 ++++++++++++++------------ app/src/main/res/values-fr/strings.xml | 9 ++++ 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/app/src/main/res/values-fr/plurals.xml b/app/src/main/res/values-fr/plurals.xml index 31a0ce3e8..c0da2ac13 100644 --- a/app/src/main/res/values-fr/plurals.xml +++ b/app/src/main/res/values-fr/plurals.xml @@ -1,31 +1,38 @@ - - Il y a %1$d minute - Il y a %1$d minutes - - - %1$d page au total - %1$d pages au total - - - %1$d élément - %1$d éléments - - - %1$d nouveau chapitre - %1$d nouveaux chapitres - - - %1$d chapitre - %1$d chapitres - - - Il y a %1$d heure - Il y a %1$d heures - - - Il y a %1$d jour - Il y a %1$d jours - - + + Il y a %1$d minute + Il y a %1$d minutes + Il y a %1$d minutes + + + %1$d page au total + %1$d pages au total + %1$d pages au total + + + %1$d élément + %1$d éléments + %1$d éléments + + + %1$d nouveau chapitre + %1$d nouveaux chapitres + %1$d nouveaux chapitres + + + %1$d chapitre + %1$d chapitres + %1$d chapitres + + + Il y a %1$d heure + Il y a %1$d heures + Il y a %1$d heures + + + Il y a %1$d jour + Il y a %1$d jours + Il y a %1$d jours + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index cd7193ee6..04f0ee800 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -417,4 +417,13 @@ Adresse Port Proxy + Téléchargé + Pseudonyme + Proxy d\'optimisation des images + Inverser les couleurs + Utilisez le service wsrv.nl pour réduire le trafic et augmenter la vitesse de chargement des images si possible + %1$s (%2$s) + Mot de passe + Valeur invalide + Autorisation (optionnel) \ No newline at end of file From de2952780559dd04f10432b57ff81083a7db59a4 Mon Sep 17 00:00:00 2001 From: GpixeL Date: Mon, 5 Jun 2023 11:53:43 +0200 Subject: [PATCH 55/94] Translated using Weblate (Indonesian) Currently translated at 100.0% (430 of 430 strings) Co-authored-by: GpixeL Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/ Translation: Kotatsu/Strings --- app/src/main/res/values-in/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index cd8f8db8a..de4eb06bd 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -131,7 +131,7 @@ Selesaikan Bersihkan kuki Semua kuki telah dihapus - Bersihkan umpan + Bersihkan aliran Periksa bab baru Masuk untuk melihat konten ini Selanjutnya @@ -215,10 +215,10 @@ Getaran Kategori favorit Hapus - Bersihkan umpan pembaruan + Bersihkan aliran pembaruan Kanan-ke-kiri Putar layar - Pembaruan umpan akan dimulai + Pembaruan aliran akan dimulai Masukkan kata sandi Tanya kata sandi ketika memulai Kotatsu Tentang From 09343632980a69ef8055b66bca3dda9c0cb41457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D0=B0=D1=80=20=D0=A0=D0=B0=D0=B7=D0=B8?= =?UTF-8?q?=D0=BD?= Date: Sun, 4 Jun 2023 12:57:01 +0200 Subject: [PATCH 56/94] Translated using Weblate (Belarusian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (421 of 421 strings) Translated using Weblate (Belarusian) Currently translated at 100.0% (416 of 416 strings) Co-authored-by: Макар Разин Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/ Translation: Kotatsu/Strings --- app/src/main/res/values-be/strings.xml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index 33e0b519d..8c17722f5 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -45,7 +45,7 @@ Тэма Светлая Цёмная - Аўтаматычна + Як у сістэме Старонкi Ачысціць Вы ўпэўненыя, што жадаеце ачысціць гісторыю\? @@ -136,8 +136,8 @@ Падагнаць па вышыні Падагнаць па шырыні Зыходны памер - Чорная цёмная тэма - Карысна для AMOLED экранаў + Чорная + Спажывае менш энергіі на экранах AMOLED Рэзервовае капіяванне і аднаўленне Стварыць рэзервовую копію Аднавіць данныя @@ -412,4 +412,9 @@ Спампоўкі былі адменены Пераклады WebView недаступны: праверце, ці ўсталяваны пастаўшчык WebView + Тып + Адрас + Порт + Проксі + Ачысціць сеткавы кэш \ No newline at end of file From e7c2a7621907e17ed4346dc5809e7b513446160a Mon Sep 17 00:00:00 2001 From: "J. Lavoie" Date: Sun, 4 Jun 2023 12:57:02 +0200 Subject: [PATCH 57/94] Translated using Weblate (French) Currently translated at 100.0% (416 of 416 strings) Co-authored-by: J. Lavoie Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/ Translation: Kotatsu/Strings --- app/src/main/res/values-fr/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index ef3ad9f8a..758eedf94 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -410,4 +410,6 @@ Les téléchargements ont été supprimés Les téléchargements ont été annulés Voulez-vous recevoir des suggestions de mangas personnalisées \? + WebView non disponible : vérifier si le fournisseur WebView est installé + Traductions \ No newline at end of file From 6bd5033858b98a0b7d5297ab67015f94355504e0 Mon Sep 17 00:00:00 2001 From: kuragehime Date: Sun, 4 Jun 2023 12:57:02 +0200 Subject: [PATCH 58/94] Translated using Weblate (Japanese) Currently translated at 100.0% (430 of 430 strings) Translated using Weblate (Japanese) Currently translated at 100.0% (427 of 427 strings) Translated using Weblate (Japanese) Currently translated at 91.8% (382 of 416 strings) Co-authored-by: kuragehime Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ja/ Translation: Kotatsu/Strings --- app/src/main/res/values-ja/strings.xml | 801 +++++++++++++------------ 1 file changed, 426 insertions(+), 375 deletions(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 8b9bc139c..160cd572a 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1,378 +1,429 @@ - 履歴 - ロード中… - チャプター %1$d of %2$d - 共有 - 履歴を削除 - 検索 - 漫画を検索 - 閉じる - お気に入り - エラーが発生しました - 詳細 - - リスト - 詳細リスト - グリッド - リストモード - リモートソース - 再試行 - 何も見つかりませんでした - まだ履歴はありません - 読む - お気に入りの本はありません - お気に入りの本 - 新たなカテゴリー - 追加 - 保存 - ショートカットを作成します… - 共有する%s - ダウンロード中… - 処理中… - ダウンロードした本 - ダウンロード - 名前 - 人気 - ローカルストレージ - 最新 - 評価 - ソート順に並べ替え - フォローシステム - クリア - すべての履歴を永久にクリアしますか? - 削除 - 「%s 」がローカルストレージから削除されました - ページを保存 - 保存しました - 画像を共有する - インポート - 消去 - この操作はサポートされていません - 説明がありません - 履歴とキャッシュ - ページのキャッシュをクリアする - B|kB|MB|GB|TB - 設定 - ライトテーマ - フィルター - ダークテーマ - ページ - テーマ - ネットワークエラー - アップデート - ZIPファイルまたはCBZファイルを選択してください。 - 標準 - ウェブトゥーン - 読み取りモード - グリッドのサイズ - %sで検索 - 漫画を削除 - お使いのデバイスから「%s」を完全に削除しますか? - リーダーの設定 - ページを変更 - エッジタップ - ボリュームボタン - 続ける - エラー - サムネイルキャッシュをクリア - クリア - ジェスチャーのみ - 内部ストレージ - ドメイン - ブラウザーで開く - この漫画には%sがあります。 すべて保存しますか? - 保存 - 通知 - %2$dの%1$d - 新しいチャプター - ダウンロード - 通知の設定 - 通知音 - LEDインジケータ - バイブレーション - お気に入りのカテゴリー - 削除 - クエリを再定式化してみてください。 - 読んだ内容がここに表示されます - サイドメニューで何を読むかを見つけてください。 - 最初に何かを保存する - 本棚 - 最近 - ページアニメーション - ダウンロード用のフォルダ - 利用出来ません - 使用可能なストレージがありません - その他のストレージ - 完了 - 全てのお気に入り - 後で読む - 更新 - あなたが読んでいるものの新しいチャプターがここに示されています - の検索結果 - サイズ:%s - 更新フィードをクリア - クリア - アップデート - フィードの更新はまもなく開始されます - アップデートを確認 - チェックしない - Kotatsuを起動したときにパスワードを入力する - パスワードを繰り返す - パスワードが違います - この本の詳細 - 現在のバージョン%s - 検索履歴をクリア - 外部ストレージ - Kotatsuの新しい更新が利用可能です - ここは空っぽです… - 空のカテゴリー - オンラインソースから保存するかファイルをインポートします。 - 新しいバージョン:%s - 画面を回転させる - パスワードを入力してください - パスワードが間違っています - アプリを保護する - 最新のアップデートを確認する - 利用可能なアップデートはありません - 右から左 - 承認済み - %sへのログインはサポートされていません - 完成 - 進行中 - デフォルト - ナンバリングページ - 使用したソース - 利用可能なソース - 新しいカテゴリー - 高さを合わせる - チャプターがありません - すべての更新履歴を完全に消去しますか? - この不足した章をダウンロードしたり、オンラインで読んだりすることができます。 - このコンテンツを表示するにはサインインしてください - ファイルが見つかりません - パスワードは4文字以上である必要があります - ちょうど今 - ずっと前 - バックアップを保存 - グループ - フィードをクリア - バックアップから復元 - 確認 - 履歴とお気に入りのバックアップを作成して復元できます - 続きを読む - ブラック - データは復元されましたがエラーが発生しました - 最近の検索クエリを全て完全に削除しますか? - 幅を合わせる - 新しいチャプターを探しています - アプリを起動するためのパスワードを入力してください - データバックアップを作成 - 解決しました - タップして再試行してください - CAPTCHAが必要です - デフォルト:%s - 昨日 - このアプリを翻訳 - 全てのデータが復元されました - 復元 - 準備中… - 開始時に維持 - バックアップと復元 - リバース - 選択した構成はこの漫画のために記憶されます - クッキーを削除 - フィットセンター - 全てのソースからログアウトされます - NSFW漫画を履歴から除外する - キュー - 全てのCookieが削除されました - 一部のデバイスはシステムでの動作が異なり、バックグラウンドタスクが中断される可能性があります。 - ジャンル - スケールモード - 今日 - Kotatsuを翻訳する(Weblateのサイトに移動します) - 次のページ - サイレント - サインイン - ようこそ - AMOLEDスクリーンでさらに少ない電力を使用 - コンピューティング… - 許可する - 常にブロック - スクリーンショットポリシー - NSFWでブロック - 提案 - すべてのデータは、このデバイス上でローカルに分析されます。お客様のデータが他のサービスに転送されることはありません - サジェスト機能を有効 - あなたの好みに合わせて漫画を提案 - ジャンルリストを読み込めません - 無効 - マンガを読み始めると、個人的な提案を受けることができます - 有効 - NSFWのマンガを提案しない - フィルターをリセット - ジャンルを探す - Wi-Fiのみ使用 - 決して - 漫画を読みたい言語を選択します。後で設定から変更することができます。 - 常に - ページのプリロード - %sとしてログイン - 18歳以上 - さまざまな言語 - チャプターを検索 - この漫画の章はありません - %1$s%% - コンテンツ - 更新のご提案 - 外観 - ジャンルを除く - サジェストで表示したくないジャンルを指定 - 選択した項目をデバイスから完全に削除しますか? - 削除が完了しました - IPアドレスのブロックを回避することができます - 保存されたマンガの処理 - ダウンロードの速度低下 - チャプターはバックグラウンドで削除されます。時間がかかる場合があります - 隠す - 新しいマンガソースが利用可能です - 新着チャプターの確認とお知らせ - 読んでいるマンガの更新情報をお知らせします - 通知を有効にする - 通知はありませんが、新しいチャプターはリストでハイライト表示されます - 名称 - 編集 - カテゴリーを編集する - お気に入りのカテゴリーはありません - ブックマーク - ブックマーク削除 - 元に戻す - 履歴から削除 - ブックマークの追加 - ブックマークの削除 - ブックマークを追加 - HTTPS 経由の DNS - リーダーモードの自動検出 - デフォルトモード - マンガがウェブトゥーンかどうかを自動判定 - バッテリー最適化の無効化 - バックグラウンドの更新チェックを支援 - 何か問題が発生しました。開発者にバグレポートを提出し、解決にご協力ください。 - 送信 - すべて無効にする - 最近読んだ漫画 - 指紋がある場合は、指紋を使用する - お気に入りの漫画 - 報告 - 読書 - 再読込 - 完了 - 保留中 - 追跡 - ログアウト - 予定 - ドロップ - データの削除 - 履歴とお気に入りに既読率を表示する - いくつかの問題の場合に助けることができる。すべての認証が無効になります - 読書の進行状況インジケーターを表示 - NSFWとマークされたマンガは履歴に追加されず、進行状況も保存されない - すべて表示 - 無効なドメイン - 範囲を選択 - コンテンツが見つからない、または削除された - 管理 - ランダム - 選択したお気に入りカテゴリを本当に削除してもよいですか? + 履歴 + ロード中… + チャプター %1$d of %2$d + 共有 + 履歴を削除 + 検索 + 漫画を検索 + 閉じる + お気に入り + エラーが発生しました + 詳細 + + リスト + 詳細リスト + グリッド + リストモード + マンガのソース + 再試行 + 何も見つかりませんでした + まだ履歴はありません + 読む + お気に入りの本はありません + お気に入りの本 + 新たなカテゴリー + 追加 + 保存 + ショートカットを作成します… + 共有する%s + ダウンロード中… + 処理中… + ダウンロードした本 + ダウンロード + 名前 + 人気 + ローカルストレージ + 最新 + 評価 + ソート順に並べ替え + フォローシステム + クリア + すべての履歴を永久にクリアしますか? + 削除 + 「%s 」がローカルストレージから削除されました + ページを保存 + 保存しました + 画像を共有する + インポート + 消去 + この操作はサポートされていません + 説明がありません + 履歴とキャッシュ + ページのキャッシュをクリアする + B|kB|MB|GB|TB + 設定 + ライトテーマ + フィルター + ダークテーマ + ページ + テーマ + ネットワークエラー + アップデート + ZIPファイルまたはCBZファイルを選択してください。 + 標準 + ウェブトゥーン + 読み取りモード + グリッドのサイズ + %sで検索 + 漫画を削除 + お使いのデバイスから「%s」を完全に削除しますか? + リーダーの設定 + ページを変更 + エッジタップ + ボリュームボタン + 続ける + エラー + サムネイルキャッシュをクリア + クリア + ジェスチャーのみ + 内部ストレージ + ドメイン + ブラウザーで開く + この漫画には%sがあります。 すべて保存しますか? + 保存 + 通知 + %2$dの%1$d + 新しいチャプター + ダウンロード + 通知の設定 + 通知音 + LEDインジケータ + バイブレーション + お気に入りのカテゴリー + 削除 + クエリを再定式化してみてください。 + 読んだ内容がここに表示されます + サイドメニューで何を読むかを見つけてください。 + 最初に何かを保存する + 本棚 + 最近 + ページアニメーション + ダウンロード用のフォルダ + 利用出来ません + 使用可能なストレージがありません + その他のストレージ + 完了 + 全てのお気に入り + 後で読む + 更新 + あなたが読んでいるものの新しいチャプターがここに示されています + の検索結果 + サイズ:%s + 更新フィードをクリア + クリア + アップデート + フィードの更新はまもなく開始されます + アップデートを確認 + チェックしない + Kotatsuを起動したときにパスワードを入力する + パスワードを繰り返す + パスワードが違います + この本の詳細 + 現在のバージョン%s + 検索履歴をクリア + 外部ストレージ + Kotatsuの新しい更新が利用可能です + ここは空っぽです… + 空のカテゴリー + オンラインソースから保存するかファイルをインポートします。 + 新しいバージョン:%s + 画面を回転させる + パスワードを入力してください + パスワードが間違っています + アプリを保護する + 最新のアップデートを確認する + 利用可能なアップデートはありません + 右から左 + 承認済み + %sへのログインはサポートされていません + 完成 + 進行中 + デフォルト + ナンバリングページ + 使用したソース + 利用可能なソース + 新しいカテゴリー + 高さを合わせる + チャプターがありません + すべての更新履歴を完全に消去しますか? + この不足した章をダウンロードしたり、オンラインで読んだりすることができます。 + このコンテンツを表示するにはサインインしてください + ファイルが見つかりません + パスワードは4文字以上である必要があります + ちょうど今 + ずっと前 + バックアップを保存 + グループ + フィードをクリア + バックアップから復元 + 確認 + 履歴とお気に入りのバックアップを作成して復元できます + 続きを読む + ブラック + データは復元されましたがエラーが発生しました + 最近の検索クエリを全て完全に削除しますか? + 幅を合わせる + 新しいチャプターを探しています + アプリを起動するためのパスワードを入力してください + データバックアップを作成 + 解決しました + タップして再試行してください + CAPTCHAが必要です + デフォルト:%s + 昨日 + このアプリを翻訳 + 全てのデータが復元されました + 復元 + 準備中… + 開始時に維持 + バックアップと復元 + リバース + 選択した構成はこの漫画のために記憶されます + クッキーを削除 + フィットセンター + 全てのソースからログアウトされます + NSFW漫画を履歴から除外する + キュー + 全てのCookieが削除されました + 一部のデバイスはシステムでの動作が異なり、バックグラウンドタスクが中断される可能性があります。 + ジャンル + スケールモード + 今日 + Kotatsuを翻訳する(Weblateのサイトに移動します) + 次のページ + サイレント + サインイン + ようこそ + AMOLEDスクリーンでさらに少ない電力を使用 + コンピューティング… + 許可する + 常にブロック + スクリーンショットポリシー + NSFWでブロック + 提案 + すべてのデータは、このデバイス上でローカルでのみ分析され、どこにも送信されることはありません。 + サジェスト機能を有効 + あなたの好みに合わせて漫画を提案 + ジャンルリストを読み込めません + 無効 + マンガを読み始めると、個人的な提案を受けることができます + 有効 + NSFWのマンガを提案しない + フィルターをリセット + ジャンルを探す + Wi-Fiのみ使用 + 決して + 漫画を読みたい言語を選択します。後で設定から変更することができます。 + 常に + ページのプリロード + %sとしてログイン + 18歳以上 + さまざまな言語 + チャプターを検索 + この漫画の章はありません + %1$s%% + コンテンツ + 更新のご提案 + 外観 + ジャンルを除く + サジェストで表示したくないジャンルを指定 + 選択した項目をデバイスから完全に削除しますか? + 削除が完了しました + IPアドレスのブロックを回避することができます + 保存されたマンガの処理 + ダウンロードの速度低下 + チャプターはバックグラウンドで削除されます + 隠す + 新しいマンガソースが利用可能です + 新着チャプターの確認とお知らせ + 読んでいるマンガの更新情報をお知らせします + 通知を有効にする + 通知はありませんが、新しいチャプターはリストでハイライト表示されます + 名称 + 編集 + カテゴリーを編集する + お気に入りのカテゴリーはありません + ブックマーク + ブックマーク削除 + 元に戻す + 履歴から削除 + ブックマークの追加 + ブックマークの削除 + ブックマークを追加 + HTTPS 経由の DNS + リーダーモードの自動検出 + デフォルトモード + マンガがウェブトゥーンかどうかを自動判定 + バッテリー最適化の無効化 + バックグラウンドの更新チェックを支援 + 何か問題が発生しました。開発者にバグレポートを提出し、解決にご協力ください。 + 送信 + すべて無効にする + 最近読んだ漫画 + 指紋がある場合は、指紋を使用する + お気に入りの漫画 + 報告 + 読書 + 再読込 + 完了 + 保留中 + 追跡 + ログアウト + 予定 + ドロップ + データの削除 + 履歴とお気に入りに既読率を表示する + いくつかの問題の場合に助けることができる。すべての認証が無効になります + 読書の進行状況インジケーターを表示 + NSFWとマークされたマンガは履歴に追加されず、進行状況も保存されない + すべて表示 + 無効なドメイン + 範囲を選択 + コンテンツが見つからない、または削除された + 管理 + ランダム + 選択したお気に入りカテゴリを本当に削除してもよいですか? \nその中にあるマンガはすべて失われ、元に戻すことはできません。 - - 探検 - アプリを終了するには、戻るを2回押してください - 保存したマンガ - チャプターなし - 自動スクロール - マンガのインポート - 続行するにはメールアドレスを入力してください - «探索»セクションで読むべきものを見つける - インポートが完了しました - あなたのマンガはここに表示されます - キャンセル - データの同期 - アカウントは既に存在します - 戻る - 過去 2 時間 - ブックマークはまだありません - 同期 - ページキャッシュ - 利用可能 - すべての履歴を消去する - 履歴が消去されました - 並べ替え - マンガを読みながらブックマークを作成することができます - ブックマークを削除しました - マンガのソースがない - マンガのソースを有効にして、オンラインでマンガを読めるようにする - もう一度戻るを押して終了します - %s -%s - 退出確認 - ストレージの使用状況 - その他のキャッシュ - シークレットモード - 画像を含むフォルダ - まもなくインポートが開始されます - お気に入りから削除 - オプション - ストレージから元のファイルを削除して、容量を節約することができます - Ch.%1$d/%2$d Pg.%3$d/%4$d - リーダーで情報バーを表示する - コミックアーカイブ - フィード - エラーの詳細:<br><tt>%1$s</tt><br><br>1. <a href=%2$s>Webブラウザで漫画を開いてみて</a>、そのソースで利用できるか確認する<br>2. 利用できる場合は、開発者にエラーレポートを送信する</a>。 - 人間工学に基づいたリーダーコントロール - 最近のマンガのショートカットを表示 - アプリケーションアイコンを長押しして最近のマンガを利用できるようにする - 右端をタップするか、右キーを押すと、常に次のページに切り替わります - 色補正 - 輝度 - コントラスト - リセット - 未保存の変更を保存または破棄しますか\? - 選択した色の設定は、この漫画のために記憶されます - 破棄 - デバイスに空き容量がありません - ページ切り替えスライダーを表示 - サーバーサイドエラー (%1$d) です。後で再試行してください - 新しいチャプターの情報も明確に - さまざまな言語 - ネットワークが利用できません - Wi-Fiまたはモバイルネットワークをオンにして、オンラインでマンガを読むことができます - Webtoonズーム - コンパクト - マミミ - - ここには何もありません - 読書の進捗状況を確認するには、マンガの詳細画面で「メニュー」→「追跡」を選択します。 - サービス - デバッグ目的でいくつかのアクションを記録する - ミク - ユーザー エージェント ヘッダー - コンテンツのプリロード - ログを共有 - 不安定な更新を許可 - アプリのベータ版へのアップデートを提案する - ダウンロードが開始されました - 言語 - ソースが無効になっています - 現在としてマーク - ログ記録を有効にする - 疑わしいコンテンツを表示する - ダイナミック - 配色 - グリッドビューで表示 - アスカ - ミオン - リッカ - さくら - この変更を適用するには、アプリケーションを再起動してください - + + 探検 + アプリを終了するには、戻るを2回押してください + 保存したマンガ + チャプターなし + 自動スクロール + マンガのインポート + 続行するにはメールアドレスを入力してください + «探索»セクションで読むべきものを見つける + インポートが完了しました + あなたのマンガはここに表示されます + キャンセル + データの同期 + アカウントは既に存在します + 戻る + 過去 2 時間 + ブックマークはまだありません + 同期 + ページキャッシュ + 利用可能 + すべての履歴を消去する + 履歴が消去されました + 並べ替え + マンガを読みながらブックマークを作成することができます + ブックマークを削除しました + マンガのソースがない + マンガのソースを有効にして、オンラインでマンガを読めるようにする + もう一度戻るを押して終了します + %s -%s + 退出確認 + ストレージの使用状況 + その他のキャッシュ + シークレットモード + 画像を含むフォルダ + まもなくインポートが開始されます + お気に入りから削除 + オプション + ストレージから元のファイルを削除して、容量を節約することができます + Ch.%1$d/%2$d Pg.%3$d/%4$d + リーダーで情報バーを表示する + コミックアーカイブ + フィード + エラーの詳細:<br><tt>%1$s</tt><br><br>1. <a href=%2$s>Webブラウザで漫画を開いてみて</a>、そのソースで利用可能かどうか確認してください<br>2.<a href=kotatsu://about>最新版のこたつ</a><br>3.利用可能であれば、開発者にエラーレポートを送ってみてください。 + 人間工学に基づいたリーダーコントロール + 最近のマンガのショートカットを表示 + アプリケーションアイコンを長押しして最近のマンガを利用できるようにする + 右端をタップするか、右キーを押すと、常に次のページに切り替わります + 色補正 + 輝度 + コントラスト + リセット + 未保存の変更を保存または破棄しますか\? + 選択した色の設定は、この漫画のために記憶されます + 破棄 + デバイスに空き容量がありません + ページ切り替えスライダーを表示 + サーバーサイドエラー (%1$d) です。後で再試行してください + 新しいチャプターの情報も明確に + さまざまな言語 + ネットワークが利用できません + Wi-Fiまたはモバイルネットワークをオンにして、オンラインでマンガを読むことができます + Webtoonズーム + コンパクト + マミミ + + ここには何もありません + 読書の進捗状況を確認するには、マンガの詳細画面で「メニュー」→「追跡」を選択します。 + サービス + デバッグ目的でいくつかのアクションを記録する + ミク + ユーザー エージェント ヘッダー + コンテンツのプリロード + ログを共有 + 不安定な更新を許可 + アプリのベータ版へのアップデートを提案する + ダウンロードが開始されました + 言語 + ソースが無効になっています + 現在としてマーク + ログ記録を有効にする + 疑わしいコンテンツを表示する + ダイナミック + 配色 + グリッドビューで表示 + アスカ + ミオン + リッカ + さくら + この変更を適用するには、アプリケーションを再起動してください + 項目をタップ&ホールドして並び替えをすることができます + .cbzまたは.zipファイルを1つ以上選択することができ、各ファイルは別のマンガとして認識されます。 + 了解 + 翻訳 + 過去に作成したユーザーデータのバックアップをインポートする + 棚に表示 + %1$s (%2$s) + 色を反転させる + 有効 + 結構です + ネットワークキャッシュをクリアする + ダウンロードは削除されました + 自分で用意した同期サーバーか、デフォルトのものを使用することができます。よく分からない場合は変更しないでください。 + 一時停止 + ダウンロードがキャンセルされました + WebViewが利用できません:WebView providerがインストールされているかどうかを確認してください + ダウンロード済み + 画像最適化プロキシ + wsrv.nl サービスを使用して、トラフィック使用量を削減し、可能であれば画像の読み込みを高速化します + アーカイブや画像のあるディレクトリを選択することができます。各アーカイブ(またはサブディレクトリ)は、1つのチャプターとして認識されます。 + 類似したものを探す + タイプ + アドレス + ポート + プロキシ + 同期の設定 + サーバーアドレス + 速度 + SSLエラーを無視する + ミラーを自動的に選択する + ミラーがある場合、エラー時にリモートソースのドメインを自動で切り替える + 履歴書 + 一時停止 + 全てキャンセル + Wi-Fi経由でのみダウンロード + モバイルデータ通信への切り替え時にダウンロードを停止する + 提案: %s + 提案されたマンガの通知を表示することがあります + もっと見る + アクティブなダウンロードはすべてキャンセルされ、部分的にダウンロードされたデータは失われます + ダウンロード履歴は完全に削除されます + ダウンロードはありません + ダウンロードが再開されました + ダウンロードが一時停止されました + パーソナライズされた漫画の提案を受け取りますか? + 削除が完了 + 既存のアカウントにサインインするか、新規にアカウントを作成することができます + 無効な値 + ユーザー名 + パスワード + オーソライズ(オプション) + \ No newline at end of file From 9c2a57812ed0eb0e1dc76cb36d9fe481a48505fe Mon Sep 17 00:00:00 2001 From: Insopitus Date: Sun, 4 Jun 2023 12:57:03 +0200 Subject: [PATCH 59/94] Translated using Weblate (Chinese (Simplified)) Currently translated at 99.2% (413 of 416 strings) Co-authored-by: Insopitus Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/ Translation: Kotatsu/Strings --- app/src/main/res/values-zh-rCN/strings.xml | 794 +++++++++++---------- 1 file changed, 412 insertions(+), 382 deletions(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 62b5a3e00..5b20c9e2a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1,385 +1,415 @@ - 设置 - 本地存储 - 喜欢 - 历史 - 发生了一个错误 - 网络错误 - 章节 - 列表 - 数据被恢复了,但有错误 - 正在处理… - 最新 - 评分 - 已删除所有 cookie - 所有数据都被恢复了 - 无声 - 准备… - 未找到文件 - 昨日 - 你可以创建你的历史和收藏的备份并恢复它 - 现在 - 很久以前 - - 轻点以重试 - 所选择的配置将因这部漫画而被记住 - 需要验证码 - 解决 - 今天 - 清除cookies - 有新的漫画源可用 - 根据你的喜好推荐漫画 - 所有的数据都在这个设备上进行本地分析,不会发送到任何地方。 - 从不 - 你会收到你正在阅读的漫画的更新通知 - 18+ - 各种语言 - 查找章节 - 排除流派 - 建议更新 - 检查新的章节并通知有关情况 - 详细内容 - 详细列表 - 网格 - 列表模式 - 漫画源 - 加载中… - 计算中… - %1$d/%2$d章节 - 关闭 - 再试一次 - 清除历史 - 没有发现 - 尚无历史 - 阅读 - 尚无收藏夹 - 收藏此漫画 - 新分类 - 添加 - 保存 - 分享 - 创建快捷方式… - 分享%s - 搜索 - 搜索漫画 - 正在下载… - 已下载 - 下载 - 名称 - 热门 - 更新 - 排序顺序 - 过滤器 - 主题 - 深色 - 浅色 - 跟随系统 - 页数 - 清除 - 永久清除所有阅读历史\? - 删除 - \"%s\"从本地存储中删除 - 保存页面 - 保存 - 分享图片 - 导入 - 删除 - 不支持此操作 - 选择 ZIP 或 CBZ 文件. - 无描述 - 历史和缓存 - 清除页面缓存 - B|kB|MB|GB|TB - 标准 - 条漫 - 阅读模式 - 网格大小 - 在%s上搜索 - 删除漫画 - 从设备中永久删除\"%s\"\? - 阅读器设置 - 切换页面 - 音量按钮 - 继续 - 边缘点击 - 错误 - 清除缩略图缓存 - 清除搜索历史 - 清除 - 仅限手势 - 内部存储 - 外部存储 - 范围 - 新版本应用程序已经推出 - 在网络浏览器中打开 - 这部漫画有%s.全部保存\? - 保存 - 通知 - 新章节 - 下载 - 通知设置 - 通知声音 - LED指示器 - 振动 - 收藏夹分类 - 删除 - 这里有点空… - 尝试重新表述查询。 - 你所读的内容将在这里显示 - 在侧面菜单中找到要读的内容. - 先保存内容 - 从在线来源保存或导入文件. - 书架 - 最近 - 页面动画 - 下载文件夹 - 不详 - 没有可用的存储空间 - 其他存储 - 完成 - 所有收藏夹 - 空分类 - 稍后阅读 - 更新 - 你正在阅读的新章节显示在这里 - 搜索结果 - 新版本: %s - 清除更新源 - 已清除 - 旋转屏幕 - 更新 - 源更新即将开始 - 查找更新 - 不要检查 - 输入密码 - 密码错误 - 保护应用程序 - 在启动Kotatsu时要求输入密码 - 重复密码 - 密码不匹配 - 关于 - 版本%s - 检查更新 - 没有更新 - 从右到左 - 新分类 - 缩放模式 - 适应中心 - 适应高度 - 适应宽度 - 从头开始 - 黑色 - 在AMOLED屏幕上使用更少电池 - 备份和还原 - 创建数据备份 - 从备份中恢复 - 恢复 - 清除文件 - 永久地清除所有的更新历史? - 检查新的章节 - 撤销 - 登录 - 登录后可查看此内容 - 默认值: %s - 下一页 - 输入密码以启动应用程序 - 确认 - 密码必须是4个字符或以上 - 永久地删除所有最近的搜索查询? - 欢迎 - 保存备份 - 一些设备有不同的系统行为, 这可能会破坏后台任务. - 阅读更多 - 排队 - 下载或在线阅读这缺失的章节. - 该章缺失 - 翻译此应用程序 - 翻译 - 授权 - 不支持在%s上登录 - 你将退出登录所有来源 - 类型 - 连载中 - 已完结 - 默认 - 将NSFW漫画排除在历史之外 - 页数 - 使用图源 - 现有图源 - 屏幕截图 - 允许 - 禁止18+ - 始终阻止 - 建议 - 启用建议 - 开始阅读漫画,你会得到个性化的建议 - 请勿推荐18+漫画 - 启用 - 禁用 - 无法加载流派列表 - 重置过滤器 - 查找流派 - 选择你想看的漫画的语言. 你可以在以后的设置中改变它. - 只在Wi-Fi上使用 - 总是 - 预加载页面 - 以%s身份登录 - 这部漫画中没有章节 - 外观 - 内容 - 指定您不希望在建议中看到的类型 - 从设备中永久删除所选项目\? - 删除已完成 - 下载速度减慢 - 有助于避免阻断你的IP地址 - 保存的漫画处理 - 章节将在后台被删除 - 隐藏 - 你将不会收到通知但新的章节将在列表中突出显示 - 启用通知 - 命名 - 编辑 - 编辑分类 - 没有收藏夹分类 - 添加书签 - 删除书签 - 书签 - 删除书签 - 添加书签 - 撤销 - 从历史中删除 - DNS over HTTPS - 默认模式 - 自动检测阅读器模式 - 自动检测漫画是否为条漫 - 禁用电池优化 - 帮助进行背景更新检查 - 出了点问题. 请向开发人员提交一份错误报告以帮助我们修复它. - 发送 - 全部禁用 - 计划 - 暂停 - 报告 - 追踪 - 注销 - 阅读 - 重读 - 完成 - 使用指纹 - 你喜欢的漫画 - 您最近阅读的漫画 - 在历史和收藏夹中显示阅读百分比 - 显示阅读进度指标 - 数据删除 - 标记为NSFW的漫画将永远不会被添加到历史中你的进度也不会被保存 - 可以在出现一些问题时提供帮助. 所有授权将被视为无效 - 显示全部 - 错误详情:<br><tt>%1$s</tt><br><br>1.尝试<a href=%2$s>在网络浏览器中打开漫画</a>以确保在其来源中可用<br>2. 请确保您使用的是<a href=kotatsu://about>最新版本的Kotatsu</a><br>3.如果可用,请向开发人员发送错误报告。 - 无效域名 - 此处将显示你的漫画 - 在【浏览】页面搜索想要阅读的漫画 - %1$s%% - 已取消 - 账号已存在 - 返回 - 同步 - 同步您的数据 - 输入您的邮箱以继续 - 已放弃 - 选择范围 - 清除所有历史 - 过去2小时 - 书签已移除 - 历史已清除 - 管理 - 还没有书签 - 您可以在阅读漫画时创建书签 - 无漫画源 - 启用漫画源以在线阅读漫画 - 随机 - 您确定要删除选定的收藏夹吗? + 设置 + 本地存储 + 喜欢 + 历史 + 发生了一个错误 + 网络错误 + 章节 + 列表 + 数据被恢复了,但有错误 + 正在处理… + 最新 + 评分 + 已删除所有 cookie + 所有数据都被恢复了 + 无声 + 准备… + 未找到文件 + 昨日 + 你可以创建你的历史和收藏的备份并恢复它 + 现在 + 很久以前 + + 轻点以重试 + 所选择的配置将因这部漫画而被记住 + 需要验证码 + 解决 + 今天 + 清除cookies + 有新的漫画源可用 + 根据你的喜好推荐漫画 + 所有的数据都在这个设备上进行本地分析,不会发送到任何地方。 + 从不 + 你会收到你正在阅读的漫画的更新通知 + 18+ + 各种语言 + 查找章节 + 排除流派 + 建议更新 + 检查新的章节并通知有关情况 + 详细内容 + 详细列表 + 网格 + 列表模式 + 漫画源 + 加载中… + 计算中… + %1$d/%2$d章节 + 关闭 + 再试一次 + 清除历史 + 没有发现 + 尚无历史 + 阅读 + 尚无收藏夹 + 收藏此漫画 + 新分类 + 添加 + 保存 + 分享 + 创建快捷方式… + 分享%s + 搜索 + 搜索漫画 + 正在下载… + 已下载 + 下载 + 名称 + 热门 + 更新 + 排序顺序 + 过滤器 + 主题 + 深色 + 浅色 + 跟随系统 + 页数 + 清除 + 永久清除所有阅读历史\? + 删除 + \"%s\"从本地存储中删除 + 保存页面 + 保存 + 分享图片 + 导入 + 删除 + 不支持此操作 + 选择 ZIP 或 CBZ 文件. + 无描述 + 历史和缓存 + 清除页面缓存 + B|kB|MB|GB|TB + 标准 + 条漫 + 阅读模式 + 网格大小 + 在%s上搜索 + 删除漫画 + 从设备中永久删除\"%s\"\? + 阅读器设置 + 切换页面 + 音量按钮 + 继续 + 边缘点击 + 错误 + 清除缩略图缓存 + 清除搜索历史 + 清除 + 仅限手势 + 内部存储 + 外部存储 + 范围 + 新版本应用程序已经推出 + 在网络浏览器中打开 + 这部漫画有%s.全部保存\? + 保存 + 通知 + 新章节 + 下载 + 通知设置 + 通知声音 + LED指示器 + 振动 + 收藏夹分类 + 删除 + 这里有点空… + 尝试重新表述查询。 + 你所读的内容将在这里显示 + 在侧面菜单中找到要读的内容. + 先保存内容 + 从在线来源保存或导入文件. + 书架 + 最近 + 页面动画 + 下载文件夹 + 不详 + 没有可用的存储空间 + 其他存储 + 完成 + 所有收藏夹 + 空分类 + 稍后阅读 + 更新 + 你正在阅读的新章节显示在这里 + 搜索结果 + 新版本: %s + 清除更新源 + 已清除 + 旋转屏幕 + 更新 + 源更新即将开始 + 查找更新 + 不要检查 + 输入密码 + 密码错误 + 保护应用程序 + 在启动Kotatsu时要求输入密码 + 重复密码 + 密码不匹配 + 关于 + 版本%s + 检查更新 + 没有更新 + 从右到左 + 新分类 + 缩放模式 + 适应中心 + 适应高度 + 适应宽度 + 从头开始 + 黑色 + 在AMOLED屏幕上使用更少电池 + 备份和还原 + 创建数据备份 + 从备份中恢复 + 恢复 + 清除文件 + 永久地清除所有的更新历史? + 检查新的章节 + 撤销 + 登录 + 登录后可查看此内容 + 默认值: %s + 下一页 + 输入密码以启动应用程序 + 确认 + 密码必须是4个字符或以上 + 永久地删除所有最近的搜索查询? + 欢迎 + 保存备份 + 一些设备有不同的系统行为, 这可能会破坏后台任务. + 阅读更多 + 排队 + 下载或在线阅读这缺失的章节. + 该章缺失 + 翻译此应用程序 + 翻译 + 授权 + 不支持在%s上登录 + 你将退出登录所有来源 + 类型 + 连载中 + 已完结 + 默认 + 将NSFW漫画排除在历史之外 + 页数 + 使用图源 + 现有图源 + 屏幕截图 + 允许 + 禁止18+ + 始终阻止 + 建议 + 启用建议 + 开始阅读漫画,你会得到个性化的建议 + 请勿推荐18+漫画 + 启用 + 禁用 + 无法加载流派列表 + 重置过滤器 + 查找流派 + 选择你想看的漫画的语言. 你可以在以后的设置中改变它. + 只在Wi-Fi上使用 + 总是 + 预加载页面 + 以%s身份登录 + 这部漫画中没有章节 + 外观 + 内容 + 指定您不希望在建议中看到的类型 + 从设备中永久删除所选项目\? + 删除已完成 + 下载速度减慢 + 有助于避免阻断你的IP地址 + 保存的漫画处理 + 章节将在后台被删除 + 隐藏 + 你将不会收到通知但新的章节将在列表中突出显示 + 启用通知 + 命名 + 编辑 + 编辑分类 + 没有收藏夹分类 + 添加书签 + 删除书签 + 书签 + 删除书签 + 添加书签 + 撤销 + 从历史中删除 + DNS over HTTPS + 默认模式 + 自动检测阅读器模式 + 自动检测漫画是否为条漫 + 禁用电池优化 + 帮助进行背景更新检查 + 出了点问题. 请向开发人员提交一份错误报告以帮助我们修复它. + 发送 + 全部禁用 + 计划 + 暂停 + 报告 + 追踪 + 注销 + 阅读 + 重读 + 完成 + 使用指纹 + 你喜欢的漫画 + 您最近阅读的漫画 + 在历史和收藏夹中显示阅读百分比 + 显示阅读进度指标 + 数据删除 + 标记为NSFW的漫画将永远不会被添加到历史中你的进度也不会被保存 + 可以在出现一些问题时提供帮助. 所有授权将被视为无效 + 显示全部 + 错误详情:<br><tt>%1$s</tt><br><br>1.尝试<a href=%2$s>在网络浏览器中打开漫画</a>以确保在其来源中可用<br>2. 请确保您使用的是<a href=kotatsu://about>最新版本的Kotatsu</a><br>3.如果可用,请向开发人员发送错误报告。 + 无效域名 + 此处将显示你的漫画 + 在【浏览】页面搜索想要阅读的漫画 + %1$s%% + 已取消 + 账号已存在 + 返回 + 同步 + 同步您的数据 + 输入您的邮箱以继续 + 已放弃 + 选择范围 + 清除所有历史 + 过去2小时 + 书签已移除 + 历史已清除 + 管理 + 还没有书签 + 您可以在阅读漫画时创建书签 + 无漫画源 + 启用漫画源以在线阅读漫画 + 随机 + 您确定要删除选定的收藏夹吗? \n所有收藏夹中的漫画将丢失且无法恢复。 - 重新排序 - 留空 - 浏览 - 自动滚动 - 在阅读器中显示信息栏 - 漫画压缩包 - 图片文件夹 - 漫画导入中 - Ch. %1$d/%2$d Pg. %3$d/%4$d - %1$d 的 %2$d 启用 - 大小:%s - 再按一次返回键退出 - 按两次返回键退出应用 - 退出确认 - 已保存漫画 - 页面缓存 - 其他缓存 - 存储占用 - 可用 - 从收藏中移除 - 选项 - 隐身模式 - 无章节 - 导入完毕 - 您可以从存储中删除原文件以节省空间 - 即将开始导入 - 订阅源 - %s - %s - 内容未找到或已移除 - 点击屏幕右侧或按下右键翻到下一页 - 高效阅读器控制 - 长按应用图标显示最近阅读的漫画 - 显示最近阅读漫画的快捷方式 - 重置 - 颜色校正 - 亮度 - 对比度 - 所选颜色设置将会应用于此漫画 - 保存还是放弃未保存的更改? - 放弃 - 设备上没有剩余空间 - 显示换页滑块 - Webtoon 缩放 - 不同语言 - 网络不可用 - 打开 Wi-Fi 或移动网络在线阅读漫画 - 同样清除新章节信息 - 服务器端错误 (%1$d)。请稍后再试 - 紧凑 - 已禁用图源 - 内容预加载 - 标为当前 - 语言 - 启用日志记录 - 分享日志 - 出于调试目的记录某些操作 - 显示可疑内容 - 动态 - 颜色方案 - 用网格视图显示 - Miku - Asuka - Mion - Rikka - Sakura - 服务 - Mamimi - Kanade - 这里什么也没有 - 要跟踪阅读进度,在漫画详情屏幕上选中“菜单→ 跟踪。 - 允许不稳定更新 - 提示更新到测试版 - 已开始下载 - UserAgent 标头 - 要应用这些更改请重启程序 - 点击并长按项目排序 - 知道了 - 速度 - 导入先前创建的用户数据备份 - 在书架上显示 - 您可以选择一个或多个cbz或zip文件,每个文件都将识别为一个单独的漫画。 - 您可以选择一个包含压缩包或图片的文件夹。每个压缩包(或子文件夹)都会被识别为一个章节。 - + 重新排序 + 留空 + 浏览 + 自动滚动 + 在阅读器中显示信息栏 + 漫画压缩包 + 图片文件夹 + 漫画导入中 + Ch. %1$d/%2$d Pg. %3$d/%4$d + %1$d 的 %2$d 启用 + 大小:%s + 再按一次返回键退出 + 按两次返回键退出应用 + 退出确认 + 已保存漫画 + 页面缓存 + 其他缓存 + 存储占用 + 可用 + 从收藏中移除 + 选项 + 隐身模式 + 无章节 + 导入完毕 + 您可以从存储中删除原文件以节省空间 + 即将开始导入 + 订阅源 + %s - %s + 内容未找到或已移除 + 点击屏幕右侧或按下右键翻到下一页 + 高效阅读器控制 + 长按应用图标显示最近阅读的漫画 + 显示最近阅读漫画的快捷方式 + 重置 + 颜色校正 + 亮度 + 对比度 + 所选颜色设置将会应用于此漫画 + 保存还是放弃未保存的更改? + 放弃 + 设备上没有剩余空间 + 显示换页滑块 + Webtoon 缩放 + 不同语言 + 网络不可用 + 打开 Wi-Fi 或移动网络在线阅读漫画 + 同样清除新章节信息 + 服务器端错误 (%1$d)。请稍后再试 + 紧凑 + 已禁用图源 + 内容预加载 + 标为当前 + 语言 + 启用日志记录 + 分享日志 + 出于调试目的记录某些操作 + 显示可疑内容 + 动态 + 颜色方案 + 用网格视图显示 + Miku + Asuka + Mion + Rikka + Sakura + 服务 + Mamimi + Kanade + 这里什么也没有 + 要跟踪阅读进度,在漫画详情屏幕上选中“菜单→ 跟踪。 + 允许不稳定更新 + 提示更新到测试版 + 已开始下载 + UserAgent 标头 + 要应用这些更改请重启程序 + 点击并长按项目排序 + 知道了 + 速度 + 导入先前创建的用户数据备份 + 在书架上显示 + 您可以选择一个或多个cbz或zip文件,每个文件都将识别为一个单独的漫画。 + 您可以选择一个包含压缩包或图片的文件夹。每个压缩包(或子文件夹)都会被识别为一个章节。 + 寻找相似 + 翻译 + WebView不可用:检查是否已安装WebView + 你可以使用自建同步服务器或默认服务器。如果你不知道自己在干什么请不要修改此处。 + 自动选择镜像 + 如果存在可用镜像,在出错时自动切换域名 + 已暂停 + 切换到移动网络时停止下载 + 移除已完成 + 取消所有 + 仅通过Wi-Fi下载 + 启用 + 不,谢谢 + 同步设定 + 服务器地址 + 暂停 + 恢复 + 忽略SSL错误 + 没有下载项 + 下载已经恢复 + 暂停下载 + 下载已被移除 + 下载被取消 + 你想要接收个人漫画推荐吗? + 推荐:%s + 偶尔对建议的漫画显示通知 + 更多 + 所有进行中的下载都将被取消,未下载完成的数据将丢失 + 你的下载历史将会永久删除 + 你可以登陆一个已有账号或创建新账号 + \ No newline at end of file From c8794d59f78e253565f5a633ef23b2025eb46f30 Mon Sep 17 00:00:00 2001 From: InfinityDouki56 Date: Sun, 4 Jun 2023 12:57:03 +0200 Subject: [PATCH 60/94] Translated using Weblate (Filipino) Currently translated at 93.0% (387 of 416 strings) Co-authored-by: InfinityDouki56 Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/ Translation: Kotatsu/Strings --- app/src/main/res/values-fil/strings.xml | 796 ++++++++++++------------ 1 file changed, 412 insertions(+), 384 deletions(-) diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml index 9c510180a..75a3e1d2f 100644 --- a/app/src/main/res/values-fil/strings.xml +++ b/app/src/main/res/values-fil/strings.xml @@ -1,387 +1,415 @@ - Na-update - Pinakabago - Maliwanag - Marka - Pansala - Tema - Madilim - Sundan ang sistema - May nangyaring error - Error sa network - Mga detalye - Mga kabanata - Listahan - Na-save - I-share ang larawan - Mag-angkat - Tanggalin - Hindi suportado ang operasyong ito - Pumili ng ZIP o CBZ file. - Kasaysayan at cache - Walang paglalarawan - Laki ng grid - Hanapin sa %s - Tanggalin ang manga - Permanenteng tanggalin ang \"%s\" sa device\? - Mga setting sa pagbasa - Magpalit ng (mga) pahina - Pindutan ng volume - Magpatuloy - I-clear ang cache ng mga thumbnail - Na-clear - Mga kilos lang - Available ang isang bagong bersyon ng app - Buksan sa web browser - Ang manga na ito ay may %s. I-save ang lahat ng ito\? - Mga abiso - %1$d ng %2$d sa - Mga bagong kabanata - Subukang i-reformulate ang query. - Ang iyong nabasa ay ipapakita dito - Ang iyong manga ay ipapakita dito - Mag-save muna ng isang bagay - I-save ito mula sa mga online na source o mag import ng mga file. - Istante - Animasyon ng pahina - Hindi magagamit - Walang available na storage - Iba pang storage - Tapos na - Lahat ng paborito - Walang laman ang kategorya - Basahin mamaya - Mga update - Mga resulta ng paghahanap - Laki: %s - I-clear ang feed ng mga update - Na-clear - Update - Ang pag update ng feed ay magsisimula sa lalong madaling panahon - Maghanap ng mga update - Ilagay ang password - Humingi ng password kapag sinimulan ang Kotatsu - Tungkol rito - Maghanap ng update - Kanan sa kaliwa - Bagong Kategorya - Pagkasyahin sa gitna - Panatilihin sa simula - Gumagamit ng mas kaunting power sa mga AMOLED na screen - I-backup at i-restore - Naibalik na - Naghahanda… - Hindi nahanap ang file - Maaari kang lumikha ng backup ng iyong kasaysayan at mga paborito at ibalik ito - Ngayon lang - Kahapon - Matagal na ang nakalipas - Ngayong araw - I-tap para subukang muli - Lutasin - Inalis ang lahat ng mga cookie - I-clear ang feed - Suriin ang mga bagong kabanata - Mag-sign in - Mag-sign in upang tingnan ang nilalamang ito - Default: %s - Susunod - Kumpirmahin - Ang password ay dapat na 4 na character o higit pa - Maligayang pagdating - Na-save ang backup - Magbasa pa - Kulang ang kabanata - Ang pag-log in sa %s ay hindi suportado - Mga genre - Patuloy - Default - Hindi isali ang NSFW manga mula sa kasaysayan - Mga pahinang may bilang - Patakaran sa screenshot - Payagan - Palaging i-block - Mga mungkahi - Paganahin ang mga mungkahi - Simulan ang pagbabasa ng manga at makakakuha ka ng mga personalized na mungkahi - Huwag magmungkahi ng NSFW manga - Pinagana - Maghanap ng genre - Pumili ng mga wika na gusto mong basahin ang manga. Maaari mo itong baguhin sa ibang pagkakataon sa mga setting. - Lokal na storage - Mga paborito - Nakaraan - Mode na listahan - Detalyadong listahan - Grid - Mga setting - Mga remote na source - Naglo-load… - Isara - Walang nahanap - Tanggalin - Bagong Kategorya - Nabasa - Wala pang paborito - I-paborito ito - Idagdag - I-save - Ibahagi - Lumikha ng shortcut… - Ibahagi sa %s - Maghanap - Maghanap ng manga - Nagda-download… - Nagpoproseso… - Na-download - Mga download - Pangalan - Sikat - Mga pahina - I-clear ang kasaysayan - I-clear ang kasaysayan ng paghahanap - Bagong bersyon: %s - Hindi tumutugma sa mga password - I-clear ang mga cookie - I-clear ang page cache - I-save - I-download - Mga setting ng abiso - Tunog ng abiso - Mga paboritong kategorya - Tanggalin - Parang walang laman dito… - Hanapin kung ano ang babasahin sa side menu. - Hanapin kung ano ang babasahin sa seksyong «Mag-explore» - Kamakailan - Folder para sa mga download - I-save ang pahina - Natanggal ang \"%s\" sa lokal na storage - Wala pang kasaysayan - Permanenteng i-clear ang lahat ng kasaysayan ng pagbabasa\? - Huwag suriin - Ulitin ang password - Protektahan ang app - Maling password - Bersyon %s - Mode ng scale - Walang available na update - Baliktarin - Grupo - Tahimik - Pagkasyahin sa lapad - Itim - Lumikha ng data backup - Ibalik mula sa backup - Naibalik ang lahat ng data - Ang data ay naibalik, ngunit may mga error - Ang napiling pagsasaayos ay maaalala para sa manga na ito - Isalin ang app na ito - Awtorisado na - Kinakailangan ang CAPTCHA - I-clear nang permanente ang lahat ng update history\? - Maglagay ng password para simulan ang app - Ang ilang device ay may iba\'t ibang gawi ng system, na maaaring masira ang mga gawain sa background. - Nakapila na - I-download o basahin ang nawawalang kabanata online. - Mala-log out ka mula sa lahat ng source - Tapos na - Alisin ang lahat ng kamakailang query sa paghahanap nang permanente\? - Pagsasalin - I-block sa NSFW - Magmungkahi ng manga batay sa iyong mga kagustuhan - Ang lahat ng data ay sinusuri nang lokal sa aparatong ito. Walang paglipat ng iyong personal na data sa anumang mga serbisyo - Hindi pinagana - Hindi ma-load ang listahan ng mga genre - I-reset ang filter - Ang mga bagong kabanata ng iyong binabasa ay makikita dito - I-rotate ang screen - Pagkasyahin sa tangkad - Hindi kailanman - Sa Wi-Fi lang - Nagco-compute… - Kabanata %1$d ng %2$d - Subukan ulit - Pag-aayos ng order - I-clear - Mga taps ng gilid - Mga ginamit na source - Magagamit na mga source - Lagi na lang - I-preload ang mga pahina - Naka-log in bilang %s - Iba\'t ibang wika - Maghanap ng kabanata - %1$s%% - Hitsura - Hindi isali ang mga genre - Tukuyin ang mga genre na hindi mo nais na makita sa mga mungkahi - Nakumpleto na ang pagtanggal - Tumutulong na maiwasan ang pag-block ng iyong IP address - Naka-save na pagproseso ng manga - Mayroon nang account - Bumalik - Pag-synchronize - Ilagay ang iyong email upang magpatuloy - Itago - May mga bagong source ng manga - Hindi ka makakatanggap ng mga abiso ngunit ang mga bagong kabanata ay iha-highlight sa mga listahan - Paganahin ang mga abiso - Ayusin ang kategorya - Tina-track - Walang mga paboritong kategorya - Mag-log out - Magdagdag ng bookmark - Tinanggal ang bookmark - Inalis sa kasaysayan - DNS sa HTTPS - Default na mode - Automatikong matukoy ang reader mode - May nangyaring mali. Mangyaring magsumite ng isang bug report sa mga developer upang matulungan kaming ayusin ito. - Ipadala - Muling pagbabasa - Binitawan - Manga mula sa iyong mga paborito - Ang iyong kamakailang nabasa na manga - Pagtanggal ng data - Ipakita ang porsyento na nabasa sa kasaysayan at mga paborito - Ipakita lahat - Pumili ng saklaw - I-clear ang lahat ng kasaysayan - Maaari kang lumikha ng bookmark habang nagbabasa ng manga - Tinanggal ang mga bookmark - Random - Walang mga source ng manga - Paganahin ang mga source ng manga upang basahin ang manga online - Ayusin muli - Walang laman - Pindutin muli ang Bumalik upang lumabas - Pindutin ang Bumalik nang dalawang beses upang lumabas sa app - Pagkumpirma ng paglabas - Na-save na manga - Mag-Explore - Iba pang cache - Paggamit ng storage - Magagamit na - %s - %s - Inalis sa mga paborito - Mga pagpipilian - Incognito mode - Walang mga kabanata - Awtomatikong pag-scroll - Ch. %1$d/%2$d Pg. %3$d/%4$d - Ipakita ang information bar sa pagbasa - Archive ng mga comics - Folder na may mga larawan - Nakumpleto na ang pag-import - Magsisimula na ang pag-import - Feed - Gawing magagamit ang kamakailang manga sa pamamagitan ng mahabang pagpindot sa icon ng application - Ipakita ang mga kamakailang manga shortcut - Ergonomic na kontrol sa mambabasa - Pagwawasto ng kulay - Liwanag - Kaibahan - I-save o kalimutan ang mga hindi na-save na pagbabago\? - Kalimutan - Walang natitirang espasyo sa device - Pag-zoom sa webtoon - Iba\'t ibang wika - Server side error (%1$d). Subukang muli mamaya - I-clear din ang impormasyon tungkol sa mga bagong kabanata - Preloading ng nilalaman - Markahan bilang kasalukuyan - Wika - Ibahagi ang mga log - Magpakita ng kahina-hinalang nilalaman - Dynamic - Ipakita sa grid view - Asuka - Mion - Rikka - Sakura - Mamimi - Kanade - Wala naman dito - Mga serbisyo - Payagan ang mga hindi stable na update - Ipakita ang mga tagapagpahiwatig ng progress ng pagbabasa - Manga na minarkahan bilang NSFW ay hindi kailanman idadagdag sa kasaysayan at ang iyong progress ay hindi mase-save - Maaaring makatulong sa kaso ng ilang mga isyu. Ang lahat ng pahintulot ay mawawalan ng bisa - Imbalidong domain - Huling 2 oras - Nabura ang kasaysayan - Pamahalaan - Wala pang bookmark - 18+ - Hindi natagpuan o inalis ang nilalaman - Magtala ng ilang pagkilos para sa mga layunin ng pag-debug - Permanenteng tanggalin ang mga napiling item sa device\? - Walang mga kabanata sa manga na ito - Nag-a-update ang mga mungkahi - Nilalaman - Pagbagal ng pag-download - Tatanggalin ang mga chapters sa background. Maaari itong tumagal ng ilang oras - Kinansela - I-sync ang iyong data - Tingnan ang mga bagong kabanata at ipaalam ang tungkol dito - Pangalan - I-edit - Tanggalin ang bookmark - Makakatanggap ka ng mga abiso tungkol sa mga update ng manga na iyong binabasa - Mag-undo - Nagbabasa - Cache ng mga pahina - Mga bookmark - Sigurado ka bang gusto mong tanggalin ang mga napiling paboritong kategorya\? + Na-update + Pinakabago + Maliwanag + Marka + Pansala + Tema + Madilim + Sundan ang sistema + May nangyaring error + Error sa network + Mga detalye + Mga kabanata + Listahan + Na-save + I-share ang larawan + Mag-angkat + Tanggalin + Hindi suportado ang operasyong ito + Pumili ng ZIP o CBZ file. + Kasaysayan at cache + Walang paglalarawan + Laki ng grid + Hanapin sa %s + Tanggalin ang manga + Permanenteng tanggalin ang \"%s\" sa device\? + Mga setting sa pagbasa + Magpalit ng (mga) pahina + Pindutan ng volume + Magpatuloy + I-clear ang cache ng mga thumbnail + Na-clear + Mga kilos lang + Available ang isang bagong bersyon ng app + Buksan sa web browser + Ang manga na ito ay may %s. I-save ang lahat ng ito\? + Mga abiso + %1$d ng %2$d sa + Mga bagong kabanata + Subukang i-reformulate ang query. + Ang iyong nabasa ay ipapakita dito + Ang iyong manga ay ipapakita dito + Mag-save muna ng isang bagay + I-save ito mula sa mga online na source o mag import ng mga file. + Istante + Animasyon ng pahina + Hindi magagamit + Walang available na storage + Iba pang storage + Tapos na + Lahat ng paborito + Walang laman ang kategorya + Basahin mamaya + Mga update + Mga resulta ng paghahanap + Laki: %s + I-clear ang feed ng mga update + Na-clear + Update + Ang pag update ng feed ay magsisimula sa lalong madaling panahon + Maghanap ng mga update + Ilagay ang password + Humingi ng password kapag sinimulan ang Kotatsu + Tungkol rito + Maghanap ng update + Kanan sa kaliwa + Bagong Kategorya + Pagkasyahin sa gitna + Panatilihin sa simula + Gumagamit ng mas kaunting power sa mga AMOLED na screen + I-backup at i-restore + Naibalik na + Naghahanda… + Hindi nahanap ang file + Maaari kang lumikha ng backup ng iyong kasaysayan at mga paborito at ibalik ito + Ngayon lang + Kahapon + Matagal na ang nakalipas + Ngayong araw + I-tap para subukang muli + Lutasin + Inalis ang lahat ng mga cookie + I-clear ang feed + Suriin ang mga bagong kabanata + Mag-sign in + Mag-sign in upang tingnan ang nilalamang ito + Default: %s + Susunod + Kumpirmahin + Ang password ay dapat na 4 na character o higit pa + Maligayang pagdating + Na-save ang backup + Magbasa pa + Kulang ang kabanata + Ang pag-log in sa %s ay hindi suportado + Mga genre + Patuloy + Default + Hindi isali ang NSFW manga mula sa kasaysayan + Mga pahinang may bilang + Patakaran sa screenshot + Payagan + Palaging i-block + Mga mungkahi + Paganahin ang mga mungkahi + Simulan ang pagbabasa ng manga at makakakuha ka ng mga personalized na mungkahi + Huwag magmungkahi ng NSFW manga + Pinagana + Maghanap ng genre + Pumili ng mga wika na gusto mong basahin ang manga. Maaari mo itong baguhin sa ibang pagkakataon sa mga setting. + Lokal na storage + Mga paborito + Kasaysayan + Mode na listahan + Detalyadong listahan + Grid + Mga setting + Mga source ng Manga + Naglo-load… + Isara + Walang nahanap + Tanggalin + Bagong Kategorya + Nabasa + Wala pang paborito + I-paborito ito + Idagdag + I-save + Ibahagi + Lumikha ng shortcut… + Ibahagi sa %s + Maghanap + Maghanap ng manga + Nagda-download… + Nagpoproseso… + Na-download + Mga download + Pangalan + Sikat + Mga pahina + I-clear ang kasaysayan + I-clear ang kasaysayan ng paghahanap + Bagong bersyon: %s + Hindi tumutugma sa mga password + I-clear ang mga cookie + I-clear ang page cache + I-save + I-download + Mga setting ng abiso + Tunog ng abiso + Mga paboritong kategorya + Tanggalin + Parang walang laman dito… + Hanapin kung ano ang babasahin sa side menu. + Hanapin kung ano ang babasahin sa seksyong «Mag-explore» + Kamakailan + Folder para sa mga download + I-save ang pahina + Natanggal ang \"%s\" sa lokal na storage + Wala pang kasaysayan + Permanenteng i-clear ang lahat ng kasaysayan ng pagbabasa\? + Huwag suriin + Ulitin ang password + Protektahan ang app + Maling password + Bersyon %s + Mode ng scale + Walang available na update + Baliktarin + Grupo + Tahimik + Pagkasyahin sa lapad + Itim + Lumikha ng data backup + Ibalik mula sa backup + Naibalik ang lahat ng data + Ang data ay naibalik, ngunit may mga error + Ang napiling pagsasaayos ay maaalala para sa manga na ito + Isalin ang app na ito + Awtorisado na + Kinakailangan ang CAPTCHA + I-clear nang permanente ang lahat ng update history\? + Maglagay ng password para simulan ang app + Ang ilang device ay may iba\'t ibang gawi ng system, na maaaring masira ang mga gawain sa background. + Nakapila na + I-download o basahin ang nawawalang kabanata online. + Mala-log out ka mula sa lahat ng source + Tapos na + Alisin ang lahat ng kamakailang query sa paghahanap nang permanente\? + Pagsasalin + I-block sa NSFW + Magmungkahi ng manga batay sa iyong mga kagustuhan + Ang lahat ng data ay lokal lamang na sinusuri sa device na ito at hindi kailanman ipinadala kahit saan. + Hindi pinagana + Hindi ma-load ang listahan ng mga genre + I-reset ang filter + Ang mga bagong kabanata ng iyong binabasa ay makikita dito + I-rotate ang screen + Pagkasyahin sa tangkad + Hindi kailanman + Sa Wi-Fi lang + Nagco-compute… + Kabanata %1$d ng %2$d + Subukan ulit + Pag-aayos ng order + I-clear + Mga taps ng gilid + Mga ginamit na source + Magagamit na mga source + Lagi na lang + I-preload ang mga pahina + Naka-log in bilang %s + Iba\'t ibang wika + Maghanap ng kabanata + %1$s%% + Hitsura + Hindi isali ang mga genre + Tukuyin ang mga genre na hindi mo nais na makita sa mga mungkahi + Nakumpleto na ang pagtanggal + Tumutulong na maiwasan ang pag-block ng iyong IP address + Naka-save na pagproseso ng manga + Mayroon nang account + Bumalik + Pag-synchronize + Ilagay ang iyong email upang magpatuloy + Itago + May mga bagong source ng manga + Hindi ka makakatanggap ng mga abiso ngunit ang mga bagong kabanata ay iha-highlight sa mga listahan + Paganahin ang mga abiso + Ayusin ang kategorya + Tina-track + Walang mga paboritong kategorya + Mag-log out + Magdagdag ng bookmark + Tinanggal ang bookmark + Inalis sa kasaysayan + DNS sa HTTPS + Default na mode + Automatikong matukoy ang reader mode + May nangyaring mali. Mangyaring magsumite ng isang bug report sa mga developer upang matulungan kaming ayusin ito. + Ipadala + Muling pagbabasa + Binitawan + Manga mula sa iyong mga paborito + Ang iyong kamakailang nabasa na manga + Pagtanggal ng data + Ipakita ang porsyento na nabasa sa kasaysayan at mga paborito + Ipakita lahat + Pumili ng saklaw + I-clear ang lahat ng kasaysayan + Maaari kang lumikha ng bookmark habang nagbabasa ng manga + Tinanggal ang mga bookmark + Random + Walang mga source ng manga + Paganahin ang mga source ng manga upang basahin ang manga online + Ayusin muli + Walang laman + Pindutin muli ang Bumalik upang lumabas + Pindutin ang Bumalik nang dalawang beses upang lumabas sa app + Pagkumpirma ng paglabas + Na-save na manga + Mag-Explore + Iba pang cache + Paggamit ng storage + Magagamit na + %s - %s + Inalis sa mga paborito + Mga pagpipilian + Incognito mode + Walang mga kabanata + Awtomatikong pag-scroll + Ch. %1$d/%2$d Pg. %3$d/%4$d + Ipakita ang information bar sa pagbasa + Archive ng mga comics + Folder na may mga larawan + Nakumpleto na ang pag-import + Magsisimula na ang pag-import + Feed + Gawing magagamit ang kamakailang manga sa pamamagitan ng mahabang pagpindot sa icon ng application + Ipakita ang mga kamakailang manga shortcut + Ergonomic na kontrol sa mambabasa + Pagwawasto ng kulay + Liwanag + Kaibahan + I-save o kalimutan ang mga hindi na-save na pagbabago\? + Kalimutan + Walang natitirang espasyo sa device + Pag-zoom sa webtoon + Iba\'t ibang wika + Server side error (%1$d). Subukang muli mamaya + I-clear din ang impormasyon tungkol sa mga bagong kabanata + Preloading ng nilalaman + Markahan bilang kasalukuyan + Wika + Ibahagi ang mga log + Magpakita ng kahina-hinalang nilalaman + Dynamic + Ipakita sa grid view + Asuka + Mion + Rikka + Sakura + Mamimi + Kanade + Wala naman dito + Mga serbisyo + Payagan ang mga hindi stable na update + Ipakita ang mga tagapagpahiwatig ng progress ng pagbabasa + Manga na minarkahan bilang NSFW ay hindi kailanman idadagdag sa kasaysayan at ang iyong progress ay hindi mase-save + Maaaring makatulong sa kaso ng ilang mga isyu. Ang lahat ng pahintulot ay mawawalan ng bisa + Imbalidong domain + Huling 2 oras + Nabura ang kasaysayan + Pamahalaan + Wala pang bookmark + 18+ + Hindi natagpuan o inalis ang nilalaman + Magtala ng ilang pagkilos para sa mga layunin ng pag-debug + Permanenteng tanggalin ang mga napiling item sa device\? + Walang mga kabanata sa manga na ito + Nag-a-update ang mga mungkahi + Nilalaman + Pagbagal ng pag-download + Tatanggalin ang mga kabanata sa background + Kinansela + I-sync ang iyong data + Tingnan ang mga bagong kabanata at ipaalam ang tungkol dito + Pangalan + I-edit + Tanggalin ang bookmark + Makakatanggap ka ng mga abiso tungkol sa mga update ng manga na iyong binabasa + Mag-undo + Nagbabasa + Cache ng mga pahina + Mga bookmark + Sigurado ka bang gusto mong tanggalin ang mga napiling paboritong kategorya\? \nAng lahat ng manga sa loob nito ay mawawala at hindi na ito mababawi. - Idinagdag ang bookmark - Awtomatikong matukoy kung ang manga ay webtoon - Huwag paganahin ang pag-optimize ng baterya - Tumutulong sa mga pagsusuri sa mga update sa background - Nakaplano - Nakumpleto na - Naka-hold - Huwag paganahin ang lahat - Gumamit ng fingerprint kung magagamit - Ulat - I-reset - Magmungkahi ng mga update sa mga beta na bersyon ng app - Hindi magagamit ang network - I-on ang Wi-Fi o mobile network para magbasa ng manga online - Mag-tap sa kanang gilid o ang pagpindot sa kanang key ay palaging lilipat sa susunod na pahina - Ipakita ang slider ng paglipat ng pahina - Mga detalye ng error:<br><tt>%1$s</tt><br><br>1. Subukang <a href=%2$s>buksan ang manga sa isang web browser</a> upang matiyak na magagamit ito sa source<br>nito 2. Kung magagamit ito, magpadala ng isang ulat ng error sa mga developer. - Paganahin ang pag-log - Hindi pinagana ang source - Pag-import ng manga - Maaari mong tanggalin ang orihinal na file mula sa storage upang makatipid ng espasyo - Ang napiling mga setting ng kulay ay matatandaan para sa manga na ito - Compact - Upang subaybayan ang pag unlad ng pagbabasa, piliin ang Menu → Track sa screen ng mga detalye ng manga. - Nagsimula na ang pag-download - Scheme ng kulay - Miku - Header ng UserAgent - B|kB|MB|GB|TB - Standard - Webtoon - Read mode - Error - Internal storage - External storage - Vibration - Domain - LED indicator - Mangyaring i-restart ang application upang ilapat ang mga pagbabagong ito - Nakuha ko - I-tap at hawakan ang isang aytem upang muling ayusin ang mga ito - Mag-import ng dating ginawa na backup ng data ng user - Ipakita sa Istante - Bilis - Maaari kang pumili ng isa o higit pang .cbz o .zip file, ang bawat file ay makikilala bilang isang hiwalay na manga. - Maaari kang pumili ng isang directory na may mga archive o mga larawan. Ang bawat archive (o subdirectory) ay makikilala bilang isang kabanata. - Maghanap ng katulad - Maaari kang mag-sign in sa isang umiiral na account o lumikha ng bago - + Idinagdag ang bookmark + Awtomatikong matukoy kung ang manga ay webtoon + Huwag paganahin ang pag-optimize ng baterya + Tumutulong sa mga pagsusuri sa mga update sa background + Nakaplano + Nakumpleto na + Naka-hold + Huwag paganahin ang lahat + Gumamit ng fingerprint kung magagamit + Ulat + I-reset + Magmungkahi ng mga update sa mga beta na bersyon ng app + Hindi magagamit ang network + I-on ang Wi-Fi o mobile network para magbasa ng manga online + Mag-tap sa kanang gilid o ang pagpindot sa kanang key ay palaging lilipat sa susunod na pahina + Ipakita ang slider ng paglipat ng pahina + Mga detalye ng error:<br><tt>%1$s</tt><br><br>1. Subukang <a href=%2$s>magbukas ng manga sa isang web browser</a> upang matiyak na available ito sa souce<br>2. Tiyaking ginagamit mo ang <a href=kotatsu://about>pinakabagong bersyon ng Kotatsu</a><br>3. Kung available ito, magpadala ng ulat ng error sa mga developer. + Paganahin ang pag-log + Hindi pinagana ang source + Pag-import ng manga + Maaari mong tanggalin ang orihinal na file mula sa storage upang makatipid ng espasyo + Ang napiling mga setting ng kulay ay matatandaan para sa manga na ito + Compact + Upang subaybayan ang pag unlad ng pagbabasa, piliin ang Menu → Track sa screen ng mga detalye ng manga. + Nagsimula na ang pag-download + Scheme ng kulay + Miku + Header ng UserAgent + B|kB|MB|GB|TB + Standard + Webtoon + Read mode + Error + Internal storage + External storage + Vibration + Domain + LED indicator + Mangyaring i-restart ang application upang ilapat ang mga pagbabagong ito + Nakuha ko + I-tap at hawakan ang isang aytem upang muling ayusin ang mga ito + Mag-import ng dating ginawa na backup ng data ng user + Ipakita sa Istante + Bilis + Maaari kang pumili ng isa o higit pang .cbz o .zip file, ang bawat file ay makikilala bilang isang hiwalay na manga. + Maaari kang pumili ng isang directory na may mga archive o mga larawan. Ang bawat archive (o subdirectory) ay makikilala bilang isang kabanata. + Maghanap ng katulad + Maaari kang mag-sign in sa isang umiiral na account o lumikha ng bago + Mga pagsasalin + Hindi available ang WebView: tingnan kung naka-install ang WebView provider + Paganahin + Na-pause ang mga pag-download + Mga setting ng pag-synchronize + Address ng server + Maaari kang gumamit ng self-hosted synchronization server o isang default. Huwag baguhin ito kung hindi ka sigurado sa iyong ginagawa. + Huwag pansinin ang mga error sa SSL + Awtomatikong pumili ng mirror + Awtomatikong lumipat ng mga domain para sa mga remote source sa mga error kung available ang mga mirror + Kanselahin lahat + Mag-download lamang sa pamamagitan ng Wi-Fi + Itigil ang pag-download kapag lumipat sa isang mobile network + Naka-pause + Tanggalin ang nakumpleto na + Mga mungkahi: %s + I-pause + Minsang magpakita ng mga notification na may iminungkahing manga + Higit pa + Salamat nalang + Ipagpatuloy + Ang lahat ng mga aktibong pag download ay kakanselahin, bahagyang na download na data ay mawawala + Permanenteng ide-delete ang iyong history ng mga pag-download + Wala kang anumang mga pag-download + Ipinagpatuloy ang mga pag-download + Gusto mo bang makatanggap ng personalized na mga mungkahi sa manga\? + Inalis na ang mga download + Nakansela ang mga pag-download + \ No newline at end of file From 7bc33adca8c30e55b2a5a302a7f3ea62619b2b11 Mon Sep 17 00:00:00 2001 From: tryvseu Date: Sun, 4 Jun 2023 12:57:04 +0200 Subject: [PATCH 61/94] Translated using Weblate (Norwegian Nynorsk) Currently translated at 85.5% (356 of 416 strings) Co-authored-by: tryvseu Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/nn/ Translation: Kotatsu/Strings --- app/src/main/res/values-nn/strings.xml | 707 +++++++++++++------------ 1 file changed, 359 insertions(+), 348 deletions(-) diff --git a/app/src/main/res/values-nn/strings.xml b/app/src/main/res/values-nn/strings.xml index 28c7e9b36..905125266 100644 --- a/app/src/main/res/values-nn/strings.xml +++ b/app/src/main/res/values-nn/strings.xml @@ -1,351 +1,362 @@ - Det hende ein feil - Rutenett - Innstillingar - Mangakjelder - Tøm historikken - Historikken er tom - Les - Lik - Ny hop - Legg til - Hent - Lag ein snarveg … - Del %s - Søk - Søk manga - Hentar … - Handsamar … - Henta - Nyaste - Omdøme - Sil ut - Ljos - Sider - Tøm - Tøm lesehistorikken for godt\? - Tak bort - Hent sida - Henta - Del biletet - Før inn - Slett - Vel ei ZIP- eller CBZ-fil. - Ingen utgreiing - Tøm mellomminnet til sida - Vanleg - Nettserie - Rutenettstorleik - Slett mangaen - Slett «%s» ifrå eininga\? - Leseinnstillingar - Bla med - Hald fram - Feil - Tøm mellomminnet for småbilete - Tøm søkehistorikken - Tømt - Berre handrørsler - Hent - Varsel - %1$d av %2$d - Hent - Varselinnstillingar - Varselljod - Varselljos - Dirring - Hopar til leiting - Hent ifrå nettkjelder eller før inn filer. - Hylla - Nytt - Legg henta mangaar i: - Gjort - Alt du likar - Tom hop - Les seinare - Oppdateringar - Søkesvar - Ny utgåve: %s - Tømt - Snu skjermen - Leit etter oppdateringar - Nei - Om - Leit etter oppdateringar - Høgre-til-venstre - Lesevising - Høv til høgda - Høv til breidda - Svart - Tryggleikskopiering og gjenoppretting - Lag ein tryggleikskopi - Gjenoppretta - Fann ikkje fila - Gjenoppretta all data - Gjenoppretta dataa, men med feil - Trykk for å røyna att - Listeslag - Henta - Likar - Historikk - Nettverksfeil - Liste - Hentar fram … - Steng - Røyn att - Fann ikkje noko - Del - Henta - Namn - Oppdatert - Vising - Lyd systemet - Mørk - Historikken og mellomminnet - Hent noko først - Ikkje tilgjengeleg - Oppdater - Storleik: %s - Brukar mindre straum på AMOLED-skjermar - Utgåve %s - Ingen tilgjengelege oppdateringar - Ny hop - Midtstill - Auk byrjinga av sida - Gjenopprett ifrå ein tryggleikskopi - Du kan tryggleikskopiera historikken og likerlista di til seinare gjenoppretting - Førebur … - Forval - No - I dag - I går - Lenge sida - Lesing - Randetrykk - Ljodstyrkeknappar - Ei ny utgåve av appen er tilgjengeleg - Opne i ein nettlesar - Denne mangaen har %s. Hent alle\? - Det du les vert vist her - Rit inn lykelordet - Gjentak lykelordet - Lykelorda er ulike - Brigde av oppsettet vedkjem berre denne mangaen - Stille - Krev CAPTCHA - Løys - Slett infokapslane - Sletta infokapslane - Tøm oppdateringshistorikken\? - Logg inn - Neste - Stadfest - Lykelordet må vera lengre enn fire teikn - Tryggleikskopi laga - Les meir - I kø - Omset denne appen - Omsetjing - Godkjend - Slag - Fullgjort - I gang - Utelèt mangaar med vakse innhald ifrå historikken - Sidetal - Nytta kjelder - Tilgjengelege kjelder - Skjermbilete - Hindre alltid - Råd - Slå på råd - Rå om mangaar ut ifrå det du har lese - Byrja å lesa nokre mangaar for å få personlege råd - Ikkje rå mangaar med vakse innhald - Påslegen - Kunne ikkje hente inn slaglista - Finn slag - Ulike mål - %1$s%% - Innhald - Oppdaterer råd - Utelat slag - Sletta - Avgrens hentesnøggleiken - Lægjer vona for at IP-adressa di vert blokkert - Handsamar henta manga - Avbroten - Kontoen finst alt - Attende - Synkroniser dataet ditt - Rit inn e-postadressa di for å halda fram - Skjul - Namn - Brigd - Brigd hopen - Sporing - Ingen likte hopar - Logg ut - Bokmerk - Tak bort bokmerket - Bokmerke - Teken bort ifrå historikken - DNS over HTTPS - Forvald lesing - Finn sjølvverkande ut av lesing - Finn sjølvverkande ut av om mangaen er ein nettserie - Slå av batterilenging - Send - Les - Skal lesa - Les att - Lesen - På vent - Gjeven opp - Slå av alle - Mangaar du har nyleg lese - Sletting av data - Vis % lesen i historikken og likerlista - Kan løysa nokre feil. Alle godkjenningar vert ugilde - Vis alle - Ugildt domene - Vel område - Tøm heile historikken - Tømte historikken - Ingen bokmerke endå - Du kan lage bokmerke medan du les - Tok bort bokmerka - Ingen mangakjelder - Slå på minst ei mangakjelde for å lesa mangaar på nett - Tilfeldig - Flytt - Tom - Trykk Attende att for å gå or appen - Utgåingsstadfesting - Mellominnet for sider - Mellomminnet for anna - Tilgjengeleg - %s - %s - Teken or likerlista - Fann ikkje innhaldet - Bla sjølvverkande - Teikneseriearkiv - Mappe med bilete - Fører inn manga - Brigd letar - Ljosstyrk - Still attende - Spar eller avvis dei usparte brigda\? - Avvis - Eininga er fylt - Vis ei rulleline til blading - Auk/mink nettseriar - Ulike mål - Nettverk ikkje tilgjengeleg - Slå på Wi-Fi eller mobilnettverk for å lesa mangaar på nett - Tjenarfeil (%1$d). Røyn att seinare - Kjelde avslegen - Hent inn innhald på forhand - Merk som aktuelt - Mål - Del loggføringar - Slå på loggføring - Tak opp nokre gjerder til bruk i istandsetjing. - Skiftande - Letar - Vis som rutenett - Rikka - Asuka - Sakura - Mamimi - Kanade - Ingenting her - Tenester - Har byrja å hente - Tøm søkehistorikken\? - Velkomen - Du vert logga ut ifrå alle kjeldane - Hindre ved vakse innhald - Slett - Her var det tomt … - Spør om lykelordet ved byrjing av appen - Feil lykelord - Vern appen - Logg inn for å sjå dette innhaldet - Vern appen med eit lykelord - All data vert handsama på eininga di og vert ikkje førte over til noka teneste - Avslegen - Vel måla du vil lesa mangaar på. Du kan brigde på dette seinare i innstillingane. - Aldri - Berre på Wi-Fi - 18+ - Alltid - Hent sider på forhand - Utsjånad - Slett valde ting ifrå eininga di\? - Logga inn som %s - Opplys om kva slags slag du ikkje vil få råd om - Synkronisering - Nye mangakjelder tilgjengelege - Du kjem til å få varsel når mangaar du les vert oppdaterte - Slå på varsel - La til eit bokmerke - Tok bort bokmerket - Angre - Nytt fingermerke om tilgjengeleg - Vis leseframgang - Mangaar du likar - Mangaar merkte med vakse innhald vert ikkje lagde til i historikken din, og framgangen din vert ikkje spart - Slett dei valde hopane\? + Det hende ein feil + Rutenett + Innstillingar + Mangakjelder + Tøm historikken + Historikken er tom + Les + Lik + Ny hop + Legg til + Hent + Lag ein snarveg … + Del %s + Søk + Søk manga + Hentar … + Handsamar … + Henta + Nyaste + Omdøme + Sil ut + Ljos + Sider + Tøm + Tøm lesehistorikken for godt\? + Tak bort + Hent sida + Henta + Del biletet + Før inn + Slett + Vel ei ZIP- eller CBZ-fil. + Ingen utgreiing + Tøm mellomminnet til sida + Vanleg + Nettserie + Rutenettstorleik + Slett mangaen + Slett «%s» ifrå eininga\? + Leseinnstillingar + Bla med + Hald fram + Feil + Tøm mellomminnet for småbilete + Tøm søkehistorikken + Tømt + Berre handvendingar + Hent + Varsel + %1$d av %2$d + Hent + Varselinnstillingar + Varselljod + Varselljos + Dirring + Hopar til leiting + Hent ifrå nettkjelder eller før inn filer. + Hylla + Nytt + Legg henta mangaar i: + Ferdig + Alt du likar + Tom hop + Les seinare + Oppdateringar + Søkesvar + Ny utgåve: %s + Tømt + Snu skjermen + Leit etter oppdateringar + Nei + Om + Leit etter oppdateringar + Høgre-til-venstre + Lesevising + Høv til høgda + Høv til breidda + Svart + Tryggleikskopiering og gjenoppretting + Lag ein tryggleikskopi + Gjenoppretta + Fann ikkje fila + Gjenoppretta all data + Gjenoppretta dataa, men med feil + Trykk for å røyna att + Listeslag + Henta + Likar + Historikk + Nettverksfeil + Liste + Hentar fram … + Steng + Røyn att + Fann ikkje noko + Del + Henta + Namn + Oppdatert + Vising + Lyd systemet + Mørk + Historikken og mellomminnet + Hent noko først + Ikkje tilgjengeleg + Oppdater + Storleik: %s + Brukar mindre straum på AMOLED-skjermar + Utgåve %s + Ingen tilgjengelege oppdateringar + Ny hop + Midtstill + Auk byrjinga av sida + Gjenopprett ifrå ein tryggleikskopi + Du kan tryggleikskopiera historikken og likerlista di til seinare gjenoppretting + Førebur … + Forval + No + I dag + I går + Lenge sida + Lesing + Randetrykk + Ljodstyrkeknappar + Ei ny utgåve av appen er tilgjengeleg + Opne i ein nettlesar + Denne mangaen har %s. Hent alle\? + Det du les vert vist her + Rit inn lykelordet + Gjentak lykelordet + Lykelorda er ulike + Brigde av oppsettet vedkjem berre denne mangaen + Stille + Krev CAPTCHA + Løys + Slett infokapslane + Sletta infokapslane + Tøm oppdateringshistorikken\? + Logg inn + Neste + Stadfest + Lykelordet må vera lengre enn fire teikn + Tryggleikskopi laga + Les meir + I kø + Omset denne appen + Omsetjing + Godkjend + Slag + Fullgjort + I gang + Utelèt mangaar med vakse innhald ifrå historikken + Sidetal + Nytta kjelder + Tilgjengelege kjelder + Skjermbilete + Hindre alltid + Råd + Slå på råd + Rå om mangaar ut ifrå det du har lese + Byrja å lesa nokre mangaar for å få personlege råd + Ikkje rå mangaar med vakse innhald + Påslegen + Kunne ikkje hente inn slaglista + Finn slag + Ulike mål + %1$s%% + Innhald + Oppdaterer råd + Utelat slag + Sletta + Avgrens hentesnøggleiken + Lægjer vona for at IP-adressa di vert blokkert + Handsamar henta manga + Avbroten + Kontoen finst alt + Attende + Synkroniser dataet ditt + Rit inn e-postadressa di for å halda fram + Skjul + Namn + Brigd + Brigd hopen + Sporing + Ingen likte hopar + Logg ut + Bokmerk + Tak bort bokmerket + Bokmerke + Teken bort ifrå historikken + DNS over HTTPS + Forvald lesing + Finn sjølvverkande ut av lesing + Finn sjølvverkande ut av om mangaen er ein nettserie + Slå av batterilenging + Send + Les + Skal lesa + Les att + Lesen + På vent + Gjeven opp + Slå av alle + Mangaar du har nyleg lese + Sletting av data + Vis % lesen i historikken og likerlista + Kan løysa nokre feil. Alle godkjenningar vert ugilde + Vis alle + Ugildt domene + Vel område + Tøm heile historikken + Tømte historikken + Ingen bokmerke endå + Du kan lage bokmerke medan du les + Tok bort bokmerka + Ingen mangakjelder + Slå på minst ei mangakjelde for å lesa mangaar på nett + Tilfeldig + Flytt + Tom + Trykk Attende att for å gå or appen + Utgåingsstadfesting + Mellominnet for sider + Mellomminnet for anna + Tilgjengeleg + %s - %s + Teken or likerlista + Fann ikkje innhaldet + Bla sjølvverkande + Teikneseriearkiv + Mappe med bilete + Fører inn manga + Brigd letar + Ljosstyrk + Still attende + Spar eller avvis dei usparte brigda\? + Avvis + Eininga er fylt + Vis ei rulleline til blading + Auk/mink nettseriar + Ulike mål + Nettverk ikkje tilgjengeleg + Slå på Wi-Fi eller mobilnettverk for å lesa mangaar på nett + Tjenarfeil (%1$d). Røyn att seinare + Kjelde avslegen + Hent inn innhald på forhand + Merk som aktuelt + Mål + Del loggføringar + Slå på loggføring + Tak opp nokre gjerder til bruk i istandsetjing. + Skiftande + Letar + Vis som rutenett + Rikka + Asuka + Sakura + Mamimi + Kanade + Ingenting her + Tenester + Har byrja å hente + Tøm søkehistorikken\? + Velkomen + Du vert logga ut ifrå alle kjeldane + Hindre ved vakse innhald + Slett + Her var det tomt … + Spør om lykelordet ved byrjing av appen + Feil lykelord + Vern appen + Logg inn for å sjå dette innhaldet + Vern appen med eit lykelord + All data vert handsama på eininga di og vert ikkje førte over til noka teneste + Avslegen + Vel måla du vil lesa mangaar på. Du kan brigde på dette seinare i innstillingane. + Aldri + Berre på Wi-Fi + 18+ + Alltid + Hent sider på forhand + Utsjånaden + Slett valde ting ifrå eininga di\? + Logga inn som %s + Opplys om kva slags slag du ikkje vil få råd om + Synkronisering + Nye mangakjelder tilgjengelege + Du kjem til å få varsel når mangaar du les vert oppdaterte + Slå på varsel + La til eit bokmerke + Tok bort bokmerket + Angre + Nytt fingermerke om tilgjengeleg + Vis leseframgang + Mangaar du likar + Mangaar merkte med vakse innhald vert ikkje lagde til i historikken din, og framgangen din vert ikkje spart + Slett dei valde hopane\? \nDu kan ikkje angre. Alle mangaane inni vert tekne ut av likerlista. - Innstillingar - Dei siste to timane - Handsam - Trykk Attende to gongar for å gå or appen - Henta mangaar - Privat modus - Førte inn - Slett den opphavlege fila for å frigjera rom - Byrjar å føra inn snart - Motsetjing - Brigde av letane vedkjem berre denne mangaen - Vis mistenksamt innhald - Mion - Miku - Byrja om appen for å nytta desse brigda - Kapittel - Utreknar… - Kapittel %1$d av %2$d - Ustødd gjerd - B|kB|MB|GB|TB - Domene - Nye kapittel - Mangaane dine vert viste her - Siderørsle - Nye kapittel av det du les vert viste her - Sjå etter nye kapittel - Siste øvst - Nokre einingar har systemåtferd som kan knuse bakgrunnsføreloger. - Hent eller les dette saknande kapittelet på nettet. - Saknar kapittelet - Finn kapittel - Ingen kapittel i denne mangaen - Kapittel vert teken bort i bakgrunnen - Sjå etter og varsle om nye kapittel - Nye kapittel vert merkte i listene utan varsel - Gransk - Ingen kapittel - Ka. %1$d/%2$d Side %3$d/%4$d - Vis opplysingsområde i lesevisinga - Trykk på høgre side eller ljodstyrke-ned-knappen blar alltid til neste side - Samantrengt - Vis i hylla - Før inn ei tryggleikskopi av brukardata - Du kan velja ei mappe med arkiv eller bilete. Kvart arkiv (eller undermappe) vert tydde som eit kapittel. - Snøggleik - Vel ei eller fleire .cbz eller .zip-filer, kvar fil vert tydde som ein eigen manga. - Tøm au opplysingar om nye kapittel - Trykk «Meny → Spor» på ei mangadetaljside for å spore leseframdrifta. - Skjønar - Trykk og hald på eit element for å flytta på det - + Innstillingar + Dei siste to timane + Handsam + Trykk Attende to gongar for å gå or appen + Henta mangaar + Privat modus + Førte inn + Slett den opphavlege fila for å frigjera rom + Byrjar å føra inn snart + Motsetjing + Brigde av letane vedkjem berre denne mangaen + Vis mistenksamt innhald + Mion + Miku + Byrja om appen for å nytta desse brigda + Kapittel + Utreknar… + Kapittel %1$d av %2$d + Ustødd gjerd + B|kB|MB|GB|TB + Domene + Nye kapittel + Mangaane dine vert viste her + Siderørsle + Nye kapittel av det du les vert viste her + Sjå etter nye kapittel + Siste øvst + Nokre einingar har systemåtferd som kan knuse bakgrunnsføreloger. + Hent eller les dette saknande kapittelet på nettet. + Saknar kapittelet + Finn kapittel + Ingen kapittel i denne mangaen + Kapittel vert teken bort i bakgrunnen + Sjå etter og varsle om nye kapittel + Nye kapittel vert merkte i listene utan varsel + Gransk + Ingen kapittel + Ka. %1$d/%2$d Side %3$d/%4$d + Vis opplysingsområde i lesevisinga + Trykk på høgre side eller ljodstyrke-ned-knappen blar alltid til neste side + Samantrengt + Vis i hylla + Før inn ei tryggleikskopi av brukardata + Du kan velja ei mappe med arkiv eller bilete. Kvart arkiv (eller undermappe) vert tydde som eit kapittel. + Snøggleik + Vel ei eller fleire .cbz eller .zip-filer, kvar fil vert tydde som ein eigen manga. + Tøm au opplysingar om nye kapittel + Trykk «Meny → Spor» på ei mangadetaljside for å spore leseframdrifta. + Skjønar + Trykk og hald på eit element for å flytta på det + Sletta «%s» ifrå eininga + Indre gøyme + Ytre gøyme + Ingen tilgjengelege gøyme + Anna gøyme + Røyn å skriva det om. + Ingen likte enno + Mest lest for tida + Søk på %s + Finn lesnadar i sidemenyen. + Finn lesnadar i «Gransk»-delen + \ No newline at end of file From 56bc0dbf075c6029e7c02ea3c41c90f4712d3dd0 Mon Sep 17 00:00:00 2001 From: Subham Jena Date: Sun, 4 Jun 2023 12:57:04 +0200 Subject: [PATCH 62/94] Translated using Weblate (Odia) Currently translated at 7.3% (31 of 421 strings) Translated using Weblate (Odia) Currently translated at 5.5% (23 of 416 strings) Co-authored-by: Subham Jena Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/or/ Translation: Kotatsu/Strings --- app/src/main/res/values-or/strings.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index d8db4f084..b55162b4b 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -11,4 +11,19 @@ ଥିମ୍ ଵେଗ ଡାଉନଲୋଡ୍ ଆରମ୍ଭ ହେଲା + ପାଠକ ସେଟିଂ + ଵିଜ୍ଞପ୍ତି + ଥାକ + ସର୍ଵଦା + ଵିଷୟଵସ୍ତୁ + ଵିଜ୍ଞପ୍ତି ସେଟିଂ + ରୂପ + ଯାଞ୍ଚ କରନି + ଅଦ୍ୟତନ ପାଇଁ ଯାଞ୍ଚ କରିବା + ଗତକାଲି + ଆଜି + ନୂଆ ଅଧ୍ୟାୟ ପାଇଁ ଯାଞ୍ଚ କରି ଏହା ଵିଷୟରେ ସୂଚିତ କରିବା + ନୂଆ ଅଧ୍ୟାୟ ପାଇଁ ଯାଞ୍ଚ କରିବା + ଫାଇଲ ମିଳୁନାହିଁ + ବ୍ୟାକଅପ୍ ଓ ପୁନରୁଦ୍ଧାର \ No newline at end of file From 6dc81468d2dbab80223a69030386005b8646d1d2 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sun, 4 Jun 2023 12:57:05 +0200 Subject: [PATCH 63/94] Translated using Weblate (Spanish) Currently translated at 100.0% (430 of 430 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (422 of 422 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (421 of 421 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (7 of 7 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (417 of 417 strings) Co-authored-by: gallegonovato Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/es/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/ Translation: Kotatsu/Strings Translation: Kotatsu/plurals --- app/src/main/res/values-es/plurals.xml | 6 +++--- app/src/main/res/values-es/strings.xml | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-es/plurals.xml b/app/src/main/res/values-es/plurals.xml index 3deb92806..f5f4a4cbb 100644 --- a/app/src/main/res/values-es/plurals.xml +++ b/app/src/main/res/values-es/plurals.xml @@ -1,9 +1,9 @@ - Total de %1$d página - Total de %1$d páginas - Total de %1$d páginas + Página total %1$d + Páginas totales %1$d + Página totales %1$d %1$d elemento diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 613c1c1f1..ae1169138 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -412,4 +412,18 @@ ¿Quieres recibir sugerencias sobre mangas personalizadas\? Traducciones WebView no está disponible: comprueba si el proveedor de WebView está instalado + Borrar la caché de la red + Tipo + Dirección + Puerto + Proxy + Valor no válido + %1$s (%2$s) + Optimización de imágenes proxy + Nombre de usuario + Descargado + Autorización (opcional) + Utiliza el servicio wsrv.nl para reducir el uso del tráfico y acelerar la carga de imágenes si es posible + Contraseña + Invertir los colores \ No newline at end of file From 3e46b3957c932de67c5a6535b286db67a541d6e3 Mon Sep 17 00:00:00 2001 From: Bai Date: Sun, 4 Jun 2023 12:57:05 +0200 Subject: [PATCH 64/94] Translated using Weblate (Turkish) Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Turkish) Currently translated at 99.7% (416 of 417 strings) Co-authored-by: Bai Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/ Translation: Kotatsu/Strings --- app/src/main/res/values-tr/strings.xml | 794 +++++++++++++------------ 1 file changed, 419 insertions(+), 375 deletions(-) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index e5685c1b8..d8eae7df3 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -1,378 +1,422 @@ - Ağ hatası - Dahili Depolama - Favoriler - Geçmiş - Bölümler - Liste - Detaylı liste - Izgara - Liste modu - Yükleniyor… - Kapat - Tekrar dene - Geçmişi temizle - Hiçbir şey bulunamadı - Geçmiş yok - Oku - Henüz favorileriniz yok - Favoriniz - Yeni kategori - Ekle - Kaydet - Paylaş - %s Paylaş - Ara - Manga ara - İndiriliyor… - İşleniyor… - İndirildi - İndirilenler - Ad - Güncellenme - Yeniler - Puanlama - Litre - Tema - Açık - Koyu - Takip sistemi - Sayfalar - Temizle - Tüm okuma geçmişi kalıcı olarak silinsin mi\? - Kaldır - “%s” yerel depolama alanından sil - Sayfayı kaydet - Resmi paylaş - Popüler - Detaylar - Ayarlar - Kaydet - Bir hata oluştu - Uzak kaynaklar - Geçmiş ve önbellek - Temizlendi - Devam - Müsait değil - Boş kategori - Kaldır - Sil - Bölüm %1$d / %2$d - Bir ZIP veya CBZ dosyası seçin. - Okuma modu - Izgara boyutu - Webtoon - B|kB|MB|GB|TB - Okuyucu ayarları - Ses butonları - Hata - Küçük resim önbelleğini temizle - Yalnızca hareketler - Alan adi - Web tarayıcısında aç - Yeni bölümler - Bildirim ayarları - Bildirim sesi - LED göstergesi - Titreşim - Diğer depolama - Güncellemeler - Kısayol oluştur… - İçe aktar - Mangayı sil - Bilgi işleniyor… - Sıralama düzeni - Açıklama yok - Bu işlem desteklenmiyor - Standart - Sayfa önbelleğini temizle - %s üzerinde ara - Dahili depolama - Bildirimler - Sayfaları değiştir - Kaydet - İndir - İndirilenler klasörü - Harici depolama - Uygulamanın yeni bir sürümü mevcut - Favori kategoriler - Bitti - Sonra oku - Sayfa animasyonu - Kullanılabilir depolama alanı yok - “%s” cihazdan kalıcı olarak silinsin mi\? - Arama geçmişini temizle - Burası biraz boş… - Ekranı döndür - Ölçek modu - Yüksekliğe sığdır - Siyah - Başlangıçta tut - Akışı temizle - Bu eksik bölümü çevrim içi olarak indirin veya okuyun. - Yedekten geri yükle - Güncelle - Oturum aç - Bitti - Hakkında - Bu içeriği görüntülemek için oturum açın - Onayla - Yetkilendirildi - Az önce - Kenar dokunuşları - Bu mangada %s var. Hepsi kaydedilsin mi\? - %1$d / %2$d açık - Sorguyu yeniden biçimlendirmeyi deneyin. - Okuduklarınız burada görüntülenecek - Yan menüde ne okuyacağınızı bulun. - Önce bir şey kaydedin - Çevrim içi kaynaklardan kaydedin veya dosyaları içe aktarın. - Raf - Son - Boyut: %s - Temizlendi - Parola gir - Kotatsu başlatılırken parola sor - Güncellemeleri ara - Güncelleme akışını temizle - Akış güncellemesi yakında başlayacak - Sürüm %s - Güncellemeleri denetle - Merkeze sığdır - Genişliğe sığdır - AMOLED ekranlarda daha az güç kullanır - Yedekle ve geri yükle - Veri yedeği oluştur - Geri yüklendi - Hazırlanıyor… - Dün - Grup - Sessiz - Çöz - Çerezleri temizle - Öntanımlı: %s - Ters - Parola 4 veya daha fazla karakterden oluşmalıdır - Hoş geldiniz - Sıraya alındı - Bölüm eksik - Bu uygulamayı çevirin - Çeviri - Devam ediyor - Tüm kaynaklardaki oturumunuz kapatılacak - Kullanılan kaynaklar - Kullanılabilir kaynaklar - Uygunsuz mangayı geçmişten hariç tut - Numaralı sayfalar - Arama sonuçları - Parolayı tekrarla - Denetleme - Yanlış parola - Geçmişinizin ve favorilerinizin yedeğini oluşturabilir ve bunları geri yükleyebilirsiniz - Uzun zaman önce - Bugün - Güncelleme yok - Tüm favoriler - Okuduklarınızın yeni bölümleri burada gösterilir - Yeni sürüm: %s - Uygulamayı koru - Parolalar eşleşmiyor - Sağdan-sola - Yeni kategori - Dosya bulunamadı - Tüm veriler geri yüklendi - Veriler geri yüklendi, ancak hatalar var - Tekrar denemek için dokunun - İleri - CAPTCHA gerekli - Tüm çerezler kaldırıldı - Seçilen yapılandırma bu manga için hatırlanacak - Tüm güncelleme geçmişi kalıcı olarak silinsin mi\? - Uygulamayı başlatmak için bir parola girin - Tüm son arama sorguları kalıcı olarak kaldırılsın mı\? - Yedek kaydedildi - Türler - Öntanımlı - %s üzerinde oturum açma desteklenmiyor - Daha fazla oku - Bazı aygıtların arka plan görevlerini bozabilecek farklı sistem davranışları vardır. - Ekran görüntüsü politikası - Uygunsuzlarda engelle - Her zaman engelle - İzin ver - Yeni bölümleri denetle - Öneriler - Önerileri etkinleştir - Tercihlerinize göre manga önerileri alın - Tüm veriler aygıt üzerinde yerel olarak işlenir. Kişisel verilerinizin herhangi bir hizmete aktarılması söz konusu değildir - Manga okumaya başladıktan sonra kişiselleştirilmiş öneriler alacaksınız - Uygunsuz manga önerme - Etkin - Devre dışı - Türler listesi yüklenemiyor - Filtreyi sıfırla - Tür bul - Manga okumak istediğiniz dilleri seçin. Daha sonra ayarlardan değiştirebilirsiniz. - Her zaman - Hiçbir zaman - Yalnızca Wi-Fi\'de - Sayfaları önceden yükle - %s olarak oturum açıldı - 18+ - Çeşitli diller - Bölüm bul - Bu mangada bölüm yok - %%%1$s - İçerik - Öneriler güncelleniyor - Görünüm - Türleri hariç tut - Önerilerde görmek istemediğiniz türleri belirtin - Seçilen ögeler aygıttan kalıcı olarak silinsin mi\? - Kaldırma tamamlandı - Bölümler arka planda kaldırılacaktır. Bu biraz zaman alabilir - İndirmeyi yavaşlat - IP adresinizin engellenmesinden kaçınmanıza yardımcı olur - Kaydedilen manga işleme - Gizle - Yeni manga kaynakları var - Bildirim almayacaksınız ancak yeni bölümler listelerde vurgulanacak - Bildirimleri etkinleştir - Yeni bölümleri denetle ve bildirim gönder - Okuduğunuz manga güncellemeleri hakkında bildirim alacaksınız - Favori kategori yok - Ad - Düzenle - Kategoriyi düzenle - Yer imi ekle - Yer imini kaldır - Yer imleri - Yer imi kaldırıldı - Yer imi eklendi - Geri al - Geçmişten kaldırıldı - HTTPS üzerinden DNS - Okuyucu modunu otomatik algıla - Manganın webtoon olup olmadığını otomatik olarak algıla - Öntanımlı mod - Pil iyileştirmesini devre dışı bırak - Arka planda güncelleme denetimlerine yardımcı olur - Bir şeyler yanlış gitti. Düzeltmemize yardımcı olması için lütfen geliştiricilere bir hata bildirimi gönderin. - Gönder - Tümünü devre dışı bırak - Varsa parmak izi kullan - Favorilerinizden mangalar - Son okuduğunuz mangalar - Bildir - İzleme - Oturumu kapat - Okunuyor - Tamamlandı - Okuma ilerleme göstergelerini göster - Verileri sil - Geçmişte ve favorilerde okunma yüzdesini göster - Uygunsuz olarak işaretlenen mangalar asla geçmişe eklenmeyecek ve ilerlemeniz kaydedilmeyecektir - Bazı sorunlarda yardımcı olabilir. Tüm yetkilendirmeler geçersiz kılınacaktır - Beklemede - Bırakıldı - Planlandı - Yeniden okunuyor - Tümünü göster - Geçersiz etki alanı - Aralık seç - İçerik bulunamadı veya kaldırıldı - Manganız burada görüntülenecek - İptal edilmiş - Hesap zaten var - Geri - Senkronizasyon - Verini yedekle - Devam etmek için E-Postanızı girin - Tüm gecmişi temizle - Son 2 saat - Geçmiş temizlendi - Yönet - Yer işareti yok - Manga okurken yer işareti oluşturabilirsiniz - Yer işaretleri kaldırıldı - Manga kaynağı yok - Çevrimiçi manga okumak için manga kaynaklarını aktif edin - Rastgele - Boş - Keşfet - Çıkmak için tekrar Geri tıkla - Çıkmak için iki defa Geri tıkla - Favorilerden kaldırıldı - Çıkış doğrulaması - Çizgi roman arşivi - Hata ayrıntıları:<br><tt>%1$s</tt><br><br>1.Mangayı <a href=%2$s>kaynağında mevcut olduğuna emin olmak için</a> bir web tarayıcısında açın<br>2. Mevcutsa, geliştiricilere bir hata reporu gönderin. - «Keşfet» kısmında neler okuyacağınızı bulun - Seçilen favori kategorileri silmek istediğinizden emin misiniz\? + Ağ hatası + Dahili Depolama + Favoriler + Geçmiş + Bölümler + Liste + Detaylı liste + Izgara + Liste modu + Yükleniyor… + Kapat + Tekrar dene + Geçmişi temizle + Hiçbir şey bulunamadı + Geçmiş yok + Oku + Henüz favorileriniz yok + Favoriniz + Yeni kategori + Ekle + Kaydet + Paylaş + %s Paylaş + Ara + Manga ara + İndiriliyor… + İşleniyor… + İndirildi + İndirilenler + Ad + Güncellenme + Yeniler + Puanlama + Litre + Tema + Açık + Koyu + Takip sistemi + Sayfalar + Temizle + Tüm okuma geçmişi kalıcı olarak silinsin mi\? + Kaldır + “%s” yerel depolama alanından sil + Sayfayı kaydet + Resmi paylaş + Popüler + Detaylar + Ayarlar + Kaydet + Bir hata oluştu + Manga kaynakları + Geçmiş ve önbellek + Temizlendi + Devam + Müsait değil + Boş kategori + Kaldır + Sil + Bölüm %1$d / %2$d + Bir ZIP veya CBZ dosyası seçin. + Okuma modu + Izgara boyutu + Webtoon + B|kB|MB|GB|TB + Okuyucu ayarları + Ses butonları + Hata + Küçük resim önbelleğini temizle + Yalnızca hareketler + Alan adi + Web tarayıcısında aç + Yeni bölümler + Bildirim ayarları + Bildirim sesi + LED göstergesi + Titreşim + Diğer depolama + Güncellemeler + Kısayol oluştur… + İçe aktar + Mangayı sil + Bilgi işleniyor… + Sıralama düzeni + Açıklama yok + Bu işlem desteklenmiyor + Standart + Sayfa önbelleğini temizle + %s üzerinde ara + Dahili depolama + Bildirimler + Sayfaları değiştir + Kaydet + İndir + İndirilenler klasörü + Harici depolama + Uygulamanın yeni bir sürümü mevcut + Favori kategoriler + Bitti + Sonra oku + Sayfa animasyonu + Kullanılabilir depolama alanı yok + “%s” cihazdan kalıcı olarak silinsin mi\? + Arama geçmişini temizle + Burası biraz boş… + Ekranı döndür + Ölçek modu + Yüksekliğe sığdır + Siyah + Başlangıçta tut + Akışı temizle + Bu eksik bölümü çevrim içi olarak indirin veya okuyun. + Yedekten geri yükle + Güncelle + Oturum aç + Bitti + Hakkında + Bu içeriği görüntülemek için oturum açın + Onayla + Yetkilendirildi + Az önce + Kenar dokunuşları + Bu mangada %s var. Hepsi kaydedilsin mi\? + %1$d / %2$d açık + Sorguyu yeniden biçimlendirmeyi deneyin. + Okuduklarınız burada görüntülenecek + Yan menüde ne okuyacağınızı bulun. + Önce bir şey kaydedin + Çevrim içi kaynaklardan kaydedin veya dosyaları içe aktarın. + Raf + Son + Boyut: %s + Temizlendi + Parola gir + Kotatsu başlatılırken parola sor + Güncellemeleri ara + Güncelleme akışını temizle + Akış güncellemesi yakında başlayacak + Sürüm %s + Güncellemeleri denetle + Merkeze sığdır + Genişliğe sığdır + AMOLED ekranlarda daha az güç kullanır + Yedekle ve geri yükle + Veri yedeği oluştur + Geri yüklendi + Hazırlanıyor… + Dün + Grup + Sessiz + Çöz + Çerezleri temizle + Öntanımlı: %s + Ters + Parola 4 veya daha fazla karakterden oluşmalıdır + Hoş geldiniz + Sıraya alındı + Bölüm eksik + Bu uygulamayı çevirin + Çeviri + Devam ediyor + Tüm kaynaklardaki oturumunuz kapatılacak + Kullanılan kaynaklar + Kullanılabilir kaynaklar + Uygunsuz mangayı geçmişten hariç tut + Numaralı sayfalar + Arama sonuçları + Parolayı tekrarla + Denetleme + Yanlış parola + Geçmişinizin ve favorilerinizin yedeğini oluşturabilir ve bunları geri yükleyebilirsiniz + Uzun zaman önce + Bugün + Güncelleme yok + Tüm favoriler + Okuduklarınızın yeni bölümleri burada gösterilir + Yeni sürüm: %s + Uygulamayı koru + Parolalar eşleşmiyor + Sağdan-sola + Yeni kategori + Dosya bulunamadı + Tüm veriler geri yüklendi + Veriler geri yüklendi, ancak hatalar var + Tekrar denemek için dokunun + İleri + CAPTCHA gerekli + Tüm çerezler kaldırıldı + Seçilen yapılandırma bu manga için hatırlanacak + Tüm güncelleme geçmişi kalıcı olarak silinsin mi\? + Uygulamayı başlatmak için bir parola girin + Tüm son arama sorguları kalıcı olarak kaldırılsın mı\? + Yedek kaydedildi + Türler + Öntanımlı + %s üzerinde oturum açma desteklenmiyor + Daha fazla oku + Bazı aygıtların arka plan görevlerini bozabilecek farklı sistem davranışları vardır. + Ekran görüntüsü politikası + Uygunsuzlarda engelle + Her zaman engelle + İzin ver + Yeni bölümleri denetle + Öneriler + Önerileri etkinleştir + Tercihlerinize göre manga önerileri alın + Tüm veriler sadece bu cihaz üzerinde yerel olarak işlenir ve asla herhangi bir yere satılmaz. + Manga okumaya başladıktan sonra kişiselleştirilmiş öneriler alacaksınız + Uygunsuz manga önerme + Etkin + Devre dışı + Türler listesi yüklenemiyor + Filtreyi sıfırla + Tür bul + Manga okumak istediğiniz dilleri seçin. Daha sonra ayarlardan değiştirebilirsiniz. + Her zaman + Hiçbir zaman + Yalnızca Wi-Fi\'de + Sayfaları önceden yükle + %s olarak oturum açıldı + 18+ + Çeşitli diller + Bölüm bul + Bu mangada bölüm yok + %%%1$s + İçerik + Öneriler güncelleniyor + Görünüm + Türleri hariç tut + Önerilerde görmek istemediğiniz türleri belirtin + Seçilen ögeler aygıttan kalıcı olarak silinsin mi\? + Kaldırma tamamlandı + Bölümler arka planda kaldırılacak. + İndirmeyi yavaşlat + IP adresinizin engellenmesinden kaçınmanıza yardımcı olur + Kaydedilen manga işleme + Gizle + Yeni manga kaynakları var + Bildirim almayacaksınız ancak yeni bölümler listelerde vurgulanacak + Bildirimleri etkinleştir + Yeni bölümleri denetle ve bildirim gönder + Okuduğunuz manga güncellemeleri hakkında bildirim alacaksınız + Favori kategori yok + Ad + Düzenle + Kategoriyi düzenle + Yer imi ekle + Yer imini kaldır + Yer imleri + Yer imi kaldırıldı + Yer imi eklendi + Geri al + Geçmişten kaldırıldı + HTTPS üzerinden DNS + Okuyucu modunu otomatik algıla + Manganın webtoon olup olmadığını otomatik olarak algıla + Öntanımlı mod + Pil iyileştirmesini devre dışı bırak + Arka planda güncelleme denetimlerine yardımcı olur + Bir şeyler yanlış gitti. Düzeltmemize yardımcı olması için lütfen geliştiricilere bir hata bildirimi gönderin. + Gönder + Tümünü devre dışı bırak + Varsa parmak izi kullan + Favorilerinizden mangalar + Son okuduğunuz mangalar + Bildir + İzleme + Oturumu kapat + Okunuyor + Tamamlandı + Okuma ilerleme göstergelerini göster + Verileri sil + Geçmişte ve favorilerde okunma yüzdesini göster + Uygunsuz olarak işaretlenen mangalar asla geçmişe eklenmeyecek ve ilerlemeniz kaydedilmeyecektir + Bazı sorunlarda yardımcı olabilir. Tüm yetkilendirmeler geçersiz kılınacaktır + Beklemede + Bırakıldı + Planlandı + Yeniden okunuyor + Tümünü göster + Geçersiz etki alanı + Aralık seç + İçerik bulunamadı veya kaldırıldı + Manganız burada görüntülenecek + İptal edilmiş + Hesap zaten var + Geri + Senkronizasyon + Verini yedekle + Devam etmek için E-Postanızı girin + Tüm gecmişi temizle + Son 2 saat + Geçmiş temizlendi + Yönet + Yer işareti yok + Manga okurken yer işareti oluşturabilirsiniz + Yer işaretleri kaldırıldı + Manga kaynağı yok + Çevrimiçi manga okumak için manga kaynaklarını aktif edin + Rastgele + Boş + Keşfet + Çıkmak için tekrar Geri tıkla + Çıkmak için iki defa Geri tıkla + Favorilerden kaldırıldı + Çıkış doğrulaması + Çizgi roman arşivi + Hata ayrıntıları:<br><tt>%1$s</tt><br><br>1.Mangayı <a href=%2$s>kaynağında mevcut olduğuna emin olmak için</a> bir web tarayıcısında açın<br>2. <a href=kotatsu://about> Kotatsunun son sürümünü kullandığnızdan emin olun.</a>/br> 3. Mevcutsa, geliştiricilere bir hata reporu gönderin. + «Keşfet» kısmında neler okuyacağınızı bulun + Seçilen favori kategorileri silmek istediğinizden emin misiniz\? \nİçindeki tüm mangalar kaybolur ve bu işlem geri alınamaz. - Yeniden sırala - Sayfa önbelleği - Diğer önbellekler - Depolama kullanımı - Mevcut - %s - %s - Seçenekler - Gizli mod - Bölüm yok - Otomatik kaydır - Böl. %1$d/%2$d Sayf. %3$d/%4$d - Okuyucuda bilgi çubuğu göster - Resimlerle klasör - Manga içe aktarılıyor - İçe aktarım tamamlandı - Yer açmak için orijinal dosyayı depolamadan silebilirsiniz - İçe aktarım birazdan başlayacak - Akış - En son manga kısayollarını göster - Ergonomik okuyucu kontrol - Renk düzeltme - Parlaklık - Kontrast - Sıfırla - Seçilen renk ayarları bu manga için hatırlanacaktır - Kaydedilmeyen değişiklikler kaydedilsin mi yoksa atılsın mı\? - Yoksay - Cihazda yer yok - Webtoon yakınlaştırma - Sayfa değiştirme kaydırıcısını göster - Ayrıca yeni bölümler hakkındaki bilgileri temizle - Sıkı - Farklı diller - Ağ kullanılamıyor - Çevrim içi manga okumak için Wi-Fi veya mobil ağı açın - Sunucu tarafı hatası (%1$d). Lütfen daha sonra tekrar deneyin - Kaydedilen mangalar - Uygulama simgesine uzun basarak son mangaları kullanılabilir hale getirin - Sağ kenara dokunulduğunda veya sağ tuşa basıldığında her zaman bir sonraki sayfaya geçilir - Kaynak devre dışı - İçerik ön yüklemesi - Geçerli olarak işaretle - Dil - Günlükleri paylaş - Günlük kaydını etkinleştir - Hata ayıklama amacıyla bazı eylemleri kaydedin - Şüpheli içeriği göster - Hizmetler - Okuma ilerlemesini izlemek için manga ayrıntıları ekranında Menü → İzle\'yi seçin. - burada hiçbir şey yok - Dinamik - renk vurgusu - Izgara görünümünde göster - Mamimi - Kanade - UserAgent başlığı - Uygulamanın beta sürümleri için güncellemeler öner - Kararsız güncellemelere izin ver - İndirme başladı - Miku - Asuka - Mion - Rikka - Sakura - Bu değişiklikleri uygulamak için lütfen uygulamayı yeniden başlatın - + Yeniden sırala + Sayfa önbelleği + Diğer önbellekler + Depolama kullanımı + Mevcut + %s - %s + Seçenekler + Gizli mod + Bölüm yok + Otomatik kaydır + Böl. %1$d/%2$d Sayf. %3$d/%4$d + Okuyucuda bilgi çubuğu göster + Resimlerle klasör + Manga içe aktarılıyor + İçe aktarım tamamlandı + Yer açmak için orijinal dosyayı depolamadan silebilirsiniz + İçe aktarım birazdan başlayacak + Akış + En son manga kısayollarını göster + Ergonomik okuyucu kontrol + Renk düzeltme + Parlaklık + Kontrast + Sıfırla + Seçilen renk ayarları bu manga için hatırlanacaktır + Kaydedilmeyen değişiklikler kaydedilsin mi yoksa atılsın mı\? + Yoksay + Cihazda yer yok + Webtoon yakınlaştırma + Sayfa değiştirme kaydırıcısını göster + Ayrıca yeni bölümler hakkındaki bilgileri temizle + Sıkı + Farklı diller + Ağ kullanılamıyor + Çevrim içi manga okumak için Wi-Fi veya mobil ağı açın + Sunucu tarafı hatası (%1$d). Lütfen daha sonra tekrar deneyin + Kaydedilen mangalar + Uygulama simgesine uzun basarak son mangaları kullanılabilir hale getirin + Sağ kenara dokunulduğunda veya sağ tuşa basıldığında her zaman bir sonraki sayfaya geçilir + Kaynak devre dışı + İçerik ön yüklemesi + Geçerli olarak işaretle + Dil + Günlükleri paylaş + Günlük kaydını etkinleştir + Hata ayıklama amacıyla bazı eylemleri kaydedin + Şüpheli içeriği göster + Hizmetler + Okuma ilerlemesini izlemek için manga ayrıntıları ekranında Menü → İzle\'yi seçin. + burada hiçbir şey yok + Dinamik + renk vurgusu + Izgara görünümünde göster + Mamimi + Kanade + UserAgent başlığı + Uygulamanın beta sürümleri için güncellemeler öner + Kararsız güncellemelere izin ver + İndirme başladı + Miku + Asuka + Mion + Rikka + Sakura + Bu değişiklikleri uygulamak için lütfen uygulamayı yeniden başlatın + Benzerini bul + Çeviriler + WebView kullanılamıyor: WebView sağlayıcısının kurulu olup olmadığını kontrol edin + Etkinleştir + Hayır teşekkürler + İnternet geçmişini temizle + Eşitleme seçenekleri + Sunucu adresi + "Şirket içinde barındırılan bir eşitleme sunucusu veya varsayılan bir sunucu kullanabilirsiniz. Ne yaptığınızdan emin değilseniz bunu değiştirmeyin." + Yansıtmalar varsa, hatalarda uzak kaynaklar için etki alanlarını otomatik olarak değiştir + Mobil ağa geçerken indirmeyi durdur + Bitirilenleri kaldır + Hepsini iptal et + Sadece Wi-Fi ile indir + Anladım + Yeniden sıralamak için bir öğeye dokunun ve basılı tutun + Bir veya daha fazla .cbz veya .zip dosyası seçebilirsiniz, her dosya ayrı bir manga olarak tanınacaktır. + Arşivler veya resimler içeren bir dizin seçebilirsiniz. Her arşiv (veya alt dizin) bir bölüm olarak tanınacaktır. + Hız + Kullanıcı verilerinin önceden oluşturulmuş bir yedeğini içe aktarın + Rafta Göster + Mevcut bir hesapta oturum açabilir veya yeni bir hesap oluşturabilirsiniz. + SSL hatalarını görmezden gel + Durdur + Devam et + Durduruldu + Öneri:%s + Bazen manga öneri bildirimlerilerini göster + Daha fazla + Tüm aktif indirmeler iptal edilecek, kısmen indirilen veriler kaybolacak + İndirme geçmişin tamamen silinecek + Hiçbir indirmeniz yok + İndirmeler devam ettirildi + İndirmeler durduruldu + İndirmeler silindi + Aynayı otomatik olarak seç + İndirmeler iptal edildi + Kişiselleştirilmiş manga önerileri almak istiyor musunuz\? + Adres + Tür + %1$s (%2$s) + Menü + Proxy + Geçersiz değer + \ No newline at end of file From 315870abcbeb0ae842ba986e38039546f5641686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D0=B0=D1=80=20=D0=A0=D0=B0=D0=B7=D0=B8?= =?UTF-8?q?=D0=BD?= Date: Sun, 4 Jun 2023 12:57:06 +0200 Subject: [PATCH 65/94] Translated using Weblate (Ukrainian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Russian) Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Belarusian) Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Polish) Currently translated at 100.0% (421 of 421 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (421 of 421 strings) Translated using Weblate (Russian) Currently translated at 100.0% (421 of 421 strings) Translated using Weblate (French) Currently translated at 100.0% (421 of 421 strings) Co-authored-by: Макар Разин Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/ Translation: Kotatsu/Strings --- app/src/main/res/values-be/strings.xml | 2 + app/src/main/res/values-fr/strings.xml | 5 + app/src/main/res/values-pl/strings.xml | 768 ++++++++++++++----------- app/src/main/res/values-ru/strings.xml | 7 + app/src/main/res/values-uk/strings.xml | 7 + 5 files changed, 439 insertions(+), 350 deletions(-) diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index 8c17722f5..63229ce62 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -417,4 +417,6 @@ Порт Проксі Ачысціць сеткавы кэш + %1$s (%2$s) + Няправільнае значэнне \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 758eedf94..cd7193ee6 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -412,4 +412,9 @@ Voulez-vous recevoir des suggestions de mangas personnalisées \? WebView non disponible : vérifier si le fournisseur WebView est installé Traductions + Effacer le cache réseau + Taper + Adresse + Port + Proxy \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index c42b524c2..9dc982b98 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1,352 +1,420 @@ - Ulubione - Historia - Napotkano błąd - Szczegółowy - Rozdziały - Lista - Lista szczegółowa - Siatka - Tryb listy - Ustawienia - Ładowanie… - Rozdział %1$d z %2$d - Zamknij - Wyczyść historię - Dodaj - Zapisz - Udostępnij - Szukaj - Szukaj mang - Pobieranie… - Pobrano - Pobrane - Nazwa - Popularność - Najnowsze - Ocena - Filtry - Jasny - Ciemny - Strony - Wyczyść - Usuń - Udostępnij zdjęcie - Usuń - Brak opisu - Tryb czytania - Błąd sieci - Obliczanie… - Spróbuj ponownie - Nic nie znaleziono - Brak historii - Czytaj - Brak ulubionych - Dodaj do ulubionych - Nowa kategoria - Stwórz skrót - Udostępnij %s - Przetwarzanie… - Zaktualizowane - Zapisz stronę - Zapisano - Wibracje - Biblioteka - Ostatnie - Tryb czarny - Przygotowywanie… - Plik nieznaleziony - Wczoraj - Dawno temu - Grupa - Dzisiaj - Zaloguj - Dalej - Potwierdź - Witaj - Skończone - W trakcie - Zezwól - Proponowane - Włącz propozycje - Włączone - Wyłączone - Nigdy - Zawsze - Znajdź rozdział - %1$s%% - Wygląd - Schowaj - Synchronizacja - Synchronizuj swoje dane - Nazwa - Edytuj - Wyloguj - Cofnij - Wyślij - Planowane - Czytane - Czytane ponownie - Skończone - Pokaż wszystkie - Wybierz zakres - Wyczyść całą historię - Ostatnie 2 godziny - Historia wyczyszczona - Zarządzaj - Losowe - Puste - Przeglądaj - Dostępne - Ustawienia - Źródło wyłączone - Kompaktowy - Błąd po stronie serwera (%1$d). Sprónuj ponownie później - Sieć niedostępna - Inne języki - Odrzuć - Jasność - Kontrast - Korekcja kolorów - Automatyczne przewijanie - Brak rozdziałów - Tryb incognito - Usunięto z ulubionych - Wykorzystana pamięć - Zapisane mangi - Brak zakładek - Możesz tworzyć zakładki w trakcie czytania mangi - Zakładki usunięte - Twoje ostatnio czytane mangi - Wyłącz wszystkie - Wyłącz optymalizację baterii - Autowykrywanie trybu czytania - Usunięte z historii - Dodano zakładkę - Usunięto zakładkę - Zakładki - Usuń zakładkę - Dodaj zakładkę - Brak ulubionych kategorii - Edytuj kategorię - Włącz powiadomienia - Wróć - Konto już istnieje - Anulowano - Zwolnienie pobierania - Brak rozdziałów w tej mandze - Różne języki - Tylko na Wi-Fi - Zawsze blokuj - Gatunki - Znajdź gatunek - Czytaj więcej - Rozwiąż - Wymagane CAPTCHA - Cichy - Dotknij aby spróbować ponownie - Teraz - Przywrócone - Dopasuj do szerokości - Dopasuj do wysokości - Dopasuj do środka - Nowa kategoria - Brak nowych aktualizacji - Sprawdź dostępność aktualizacji - Wersja %s - O aplikacji - Usuń - Jest tu dosyć pusto… - Ulubione kategorie - Powiadomienie LED - Nowe rozdziały - Pamięć wewnętrzna - Tutaj będą wyświetlane Twoje mangi - Znajdź materiały do czytania w zakładce „Przeglądaj” - W tym miejscu pojawią się powiadomienia o nowych rozdziałach z mang które czytasz - Strony w pamięci podręcznej - Animacja przewracania strony - Inne rzeczy w pamięci podręcznej - Otwórz w przeglądarce - Numerowane strony - Powiadomienia - Dźwięk powiadomień - Ustawienia powiadomień - Zewnętrzne źródła - Motyw - Systemowy - Historia i pamięć podręczna - Wyczyść pamięć podręczną stron - B|kB|MB|GB|TB - Wielkość siatki - Szukaj na %s - Usuń mangę - Dalej - Błąd - Wyczyszczone - Pamięć wewnętrzna - Pamięć zewnętrzna - Domena - Nowa wersja aplikacji jest dostępna - Ta manga ma %s. Zapisać wszystko? - Zapisz - Pobierz - Najpierw coś zapisz - Niedostępne - Zapisz - Wszystkie ulubione - Pusta kategoria - Czytaj później - Aktualizacje - Nowa wersja: %s - Wielkość: %s - Obróć ekran - Odśwież - Szukaj aktualizacji - Nie sprawdzaj - Wprowadź hasło - Złe hasło - Chroń aplikację - Pytaj o hasło przy starcie Kotatsu - Wprowadź ponownie hasło - Zużywa mniej prądu na ekranach AMOLED - Kopia zapasowa i przywracanie - Utwórz kopię zapasową danych - Przywróć z kopii zapasowej - 18+ - %1$d na %2$d włączone - Standardowy - Webtoon - Ustawienia czytnika - Zmiana strony - Przyciski głośności - Dotknięcie krawędzi - Wyczyszczone - Tryb skalowania - Wyczyść ciasteczka - Wszystkie ciasteczka wyczyszczone - Przetłumacz tą aplikację - Tłumaczenie - Dostępne źródła - Tylko gesty - Brak dostępnej pamięci - Inny - Wyniki wyszukiwania - Wszystkie dane zostały przywrócone - Dane zostały przywrócone, ale z błędami - Od tyłu - Domyślny - Polityka zrzutów ekranu - Wyklucz gatunki - Określ gatunki, których nie chcesz widzieć w sugestiach - Zalogowano jako %s - Wybierz języki, w których chcesz czytać mangi. Możesz zmienić to później w ustawieniach. - Zgłoś - Usuwanie danych - Nieważna domena - Zmień kolejność - Potwierdzenie wyjścia - %s - %s - Rozdz. %1$d/%2$d Str. %3$d/%4$d - Włącz Wi-Fi lub sieć komórkową, aby czytać mangę online - Importuj - Wybierz plik ZIP lub CBZ. - Wyczyść historię wyszukiwania - Ta operacja nie jest obsługiwana - Tryb sortowania - Treści - Nie można załadować listy gatunków - Wstrzymane - Porzucone - Użyj odcisku palca, jeśli jest dostępny - Mangi z Twoich ulubionych - Pokaż wskaźniki postępu czytania - Pokaż procent przeczytania w historii i ulubionych - Manga oznaczona jako NSFW nigdy nie zostanie dodana do historii, a Twoje postępy nie zostaną zapisane - DNS przez HTTPS - Tryb domyślny - Trwale wyczyścić całą historię czytania? - „%s” usunięte z pamięci lokalnej - Wyczyść tablicę aktualizacji - Tablica - Usunąć trwale „%s” z urządzenia? - Wyczyść pamięć podręczną miniatur - Spróbuj przeformułować zapytanie. - To co czytasz będzie wyświetlane tutaj - Znajdź to, co warto przeczytać, w menu bocznym. - Zapisz ze źródeł online lub zaimportuj pliki. - Folder pobranych - Aktualizacja tablicy rozpocznie się wkrótce - Niezgodne hasła - Od prawej do lewej - Trzymaj na starcie - Możesz utworzyć kopię zapasową swojej historii i ulubionych oraz przywrócić ją - Wybrana konfiguracja zostanie zapamiętana dla tej mangi - Wyczyść tablicę - Wyczyścić trwale całą historię aktualizacji? - Szukanie nowych rozdziałów - Zaloguj się, aby wyświetlić tę zawartość - Domyślnie: %s - Wprowadź hasło, aby uruchomić aplikację - Hasło musi mieć co najmniej 4 znaki - Trwale usunąć wszystkie ostatnie zapytania wyszukiwania? - Zapisano kopię zapasową - Systemy niektórych urządzeń inaczej się zachowują. Może to zakłócać wykonywanie zadań w tle. - W kolejce - Pobierz lub przeczytaj ten brakujący rozdział online. - Brak rozdziału - Uprawniony - Logowanie na %s nie jest obsługiwane - Zostaniesz wylogowany ze wszystkich źródeł - Wyklucz mangi NSFW z historii - Wykorzystane źródła - Zablokuj na NSFW - Proponuj mangi na podstawie Twoich preferencji - Wszystkie dane są analizowane lokalnie na tym urządzeniu. Twoje dane osobowe nie są przekazywane do żadnych usług - Zacznij czytać mangę, a otrzymasz spersonalizowane sugestie - Nie proponuj mang NSFW - Zresetuj filtr - Ładuj wstępnie strony - Aktualizowanie sugestii - Trwale usunąć wybrane elementy z urządzenia? - Usuwanie zakończone - Pomaga uniknąć blokowania Twojego adresu IP - Przetwarzanie zapisanej mangi - Rozdziały zostaną usunięte w tle. Może to zająć trochę czasu - Wpisz swój adres e-mail, aby kontynuować - Dostępne są nowe źródła mang - Sprawdzaj dostępność nowych rozdziałów i informuj o nich - Będziesz otrzymywać powiadomienia o aktualizacjach mang, które czytasz - Nie będziesz otrzymywać powiadomień, ale nowe rozdziały będą podświetlane na listach - Śledzenie - Automatycznie wykryj, czy manga to webtoon - Pomaga w sprawdzaniu aktualizacji w tle - Coś poszło nie tak. Zgłoś błąd programistom, aby pomóc nam go naprawić. - Może pomóc w przypadku niektórych problemów. Wszystkie autoryzacje zostaną unieważnione - Brak źródeł mang - Włącz źródła mang do czytania mang online - Czy na pewno chcesz usunąć wybrane ulubione kategorie? Wszystkie w nich mangi zostaną usunięte i nie będzie można tego cofnąć. - Naciśnij ponownie Wstecz, aby wyjść - Naciśnij dwukrotnie przycisk Wstecz, aby wyjść z aplikacji - Treść nie została znaleziona lub została usunięta - Pokaż pasek informacji w czytniku - Archiwum komiksów - Folder z obrazami - Importowanie mangi - Importowanie zakończone - Możesz usunąć oryginalny plik z pamięci, aby zaoszczędzić miejsce - Import rozpocznie się wkrótce - Wybrane ustawienia kolorów zostaną zapamiętane dla tej mangi - Pokaż ostatnie skróty do mang - Pokaż ostatnie mangi po długim naciśnięciu ikony aplikacji - Stuknięcie w prawą krawędź lub naciśnięcie prawego klawisza zawsze powoduje przejście do następnej strony - Ergonomiczne sterowanie czytnikiem - Zapisać czy odrzucić niezapisane zmiany? - Brak miejsca w urządzeniu - Pokaż suwak przełączania stron - Powiększanie webtoon - Wyczyść też informacje o nowych rozdziałach - Resetuj - Szczegóły błędu:<br><tt>%1$s</tt><br><br>1. Spróbuj <a href=%2$s>otworzyć mangę w przeglądarce internetowej</a> aby upewnić się, że jest dostępna w źródle<br>2. Jeśli jest dostępna, wyślij raport o błędzie do programistów. - + Ulubione + Historia + Napotkano błąd + Szczegółowy + Rozdziały + Lista + Lista szczegółowa + Siatka + Tryb listy + Ustawienia + Ładowanie… + Rozdział %1$d z %2$d + Zamknij + Wyczyść historię + Dodaj + Zapisz + Udostępnij + Szukaj + Szukaj mang + Pobieranie… + Pobrano + Pobrane + Nazwa + Popularność + Najnowsze + Ocena + Filtry + Jasny + Ciemny + Strony + Wyczyść + Usuń + Udostępnij zdjęcie + Usuń + Brak opisu + Tryb czytania + Błąd sieci + Obliczanie… + Spróbuj ponownie + Nic nie znaleziono + Brak historii + Czytaj + Brak ulubionych + Dodaj do ulubionych + Nowa kategoria + Stwórz skrót… + Udostępnij %s + Przetwarzanie… + Zaktualizowane + Zapisz stronę + Zapisano + Wibracje + Biblioteka + Ostatnie + Tryb czarny + Przygotowywanie… + Plik nieznaleziony + Wczoraj + Dawno temu + Grupa + Dzisiaj + Zaloguj + Dalej + Potwierdź + Witaj + Skończone + W trakcie + Zezwól + Proponowane + Włącz propozycje + Włączone + Wyłączone + Nigdy + Zawsze + Znajdź rozdział + %1$s%% + Wygląd + Schowaj + Synchronizacja + Synchronizuj swoje dane + Nazwa + Edytuj + Wyloguj + Cofnij + Wyślij + Planowane + Czytane + Czytane ponownie + Skończone + Pokaż wszystkie + Wybierz zakres + Wyczyść całą historię + Ostatnie 2 godziny + Historia wyczyszczona + Zarządzaj + Losowe + Puste + Przeglądaj + Dostępne + Ustawienia + Źródło wyłączone + Kompaktowy + Błąd po stronie serwera (%1$d). Sprónuj ponownie później + Sieć niedostępna + Inne języki + Odrzuć + Jasność + Kontrast + Korekcja kolorów + Automatyczne przewijanie + Brak rozdziałów + Tryb incognito + Usunięto z ulubionych + Wykorzystana pamięć + Zapisane mangi + Brak zakładek + Możesz tworzyć zakładki w trakcie czytania mangi + Zakładki usunięte + Twoje ostatnio czytane mangi + Wyłącz wszystkie + Wyłącz optymalizację baterii + Autowykrywanie trybu czytania + Usunięte z historii + Dodano zakładkę + Usunięto zakładkę + Zakładki + Usuń zakładkę + Dodaj zakładkę + Brak ulubionych kategorii + Edytuj kategorię + Włącz powiadomienia + Wróć + Konto już istnieje + Anulowano + Zwolnienie pobierania + Brak rozdziałów w tej mandze + Różne języki + Tylko na Wi-Fi + Zawsze blokuj + Gatunki + Znajdź gatunek + Czytaj więcej + Rozwiąż + Wymagane CAPTCHA + Cichy + Dotknij aby spróbować ponownie + Teraz + Przywrócone + Dopasuj do szerokości + Dopasuj do wysokości + Dopasuj do środka + Nowa kategoria + Brak nowych aktualizacji + Sprawdź dostępność aktualizacji + Wersja %s + O aplikacji + Usuń + Jest tu dosyć pusto… + Ulubione kategorie + Powiadomienie LED + Nowe rozdziały + Pamięć wewnętrzna + Tutaj będą wyświetlane Twoje mangi + Znajdź materiały do czytania w zakładce „Przeglądaj” + W tym miejscu pojawią się powiadomienia o nowych rozdziałach z mang które czytasz + Strony w pamięci podręcznej + Animacja przewracania strony + Inne rzeczy w pamięci podręcznej + Otwórz w przeglądarce + Numerowane strony + Powiadomienia + Dźwięk powiadomień + Ustawienia powiadomień + Zewnętrzne źródła + Motyw + Systemowy + Historia i pamięć podręczna + Wyczyść pamięć podręczną stron + B|kB|MB|GB|TB + Wielkość siatki + Szukaj na %s + Usuń mangę + Dalej + Błąd + Wyczyszczone + Pamięć wewnętrzna + Pamięć zewnętrzna + Domena + Nowa wersja aplikacji jest dostępna + Ta manga ma %s. Zapisać wszystko? + Zapisz + Pobierz + Najpierw coś zapisz + Niedostępne + Zapisz + Wszystkie ulubione + Pusta kategoria + Czytaj później + Aktualizacje + Nowa wersja: %s + Wielkość: %s + Obróć ekran + Odśwież + Szukaj aktualizacji + Nie sprawdzaj + Wprowadź hasło + Złe hasło + Chroń aplikację + Pytaj o hasło przy starcie Kotatsu + Wprowadź ponownie hasło + Zużywa mniej prądu na ekranach AMOLED + Kopia zapasowa i przywracanie + Utwórz kopię zapasową danych + Przywróć z kopii zapasowej + 18+ + %1$d na %2$d włączone + Standardowy + Webtoon + Ustawienia czytnika + Zmiana strony + Przyciski głośności + Dotknięcie krawędzi + Wyczyszczone + Tryb skalowania + Wyczyść ciasteczka + Wszystkie ciasteczka wyczyszczone + Przetłumacz tą aplikację + Tłumaczenie + Dostępne źródła + Tylko gesty + Brak dostępnej pamięci + Inny + Wyniki wyszukiwania + Wszystkie dane zostały przywrócone + Dane zostały przywrócone, ale z błędami + Od tyłu + Domyślny + Polityka zrzutów ekranu + Wyklucz gatunki + Określ gatunki, których nie chcesz widzieć w sugestiach + Zalogowano jako %s + Wybierz języki, w których chcesz czytać mangi. Możesz zmienić to później w ustawieniach. + Zgłoś + Usuwanie danych + Nieważna domena + Zmień kolejność + Potwierdzenie wyjścia + %s - %s + Rozdz. %1$d/%2$d Str. %3$d/%4$d + Włącz Wi-Fi lub sieć komórkową, aby czytać mangę online + Importuj + Wybierz plik ZIP lub CBZ. + Wyczyść historię wyszukiwania + Ta operacja nie jest obsługiwana + Tryb sortowania + Treści + Nie można załadować listy gatunków + Wstrzymane + Porzucone + Użyj odcisku palca, jeśli jest dostępny + Mangi z Twoich ulubionych + Pokaż wskaźniki postępu czytania + Pokaż procent przeczytania w historii i ulubionych + Manga oznaczona jako NSFW nigdy nie zostanie dodana do historii, a Twoje postępy nie zostaną zapisane + DNS przez HTTPS + Tryb domyślny + Trwale wyczyścić całą historię czytania? + „%s” usunięte z pamięci lokalnej + Wyczyść tablicę aktualizacji + Tablica + Usunąć trwale „%s” z urządzenia? + Wyczyść pamięć podręczną miniatur + Spróbuj przeformułować zapytanie. + To co czytasz będzie wyświetlane tutaj + Znajdź to, co warto przeczytać, w menu bocznym. + Zapisz ze źródeł online lub zaimportuj pliki. + Folder pobranych + Aktualizacja tablicy rozpocznie się wkrótce + Niezgodne hasła + Od prawej do lewej + Trzymaj na starcie + Możesz utworzyć kopię zapasową swojej historii i ulubionych oraz przywrócić ją + Wybrana konfiguracja zostanie zapamiętana dla tej mangi + Wyczyść tablicę + Wyczyścić trwale całą historię aktualizacji? + Szukanie nowych rozdziałów + Zaloguj się, aby wyświetlić tę zawartość + Domyślnie: %s + Wprowadź hasło, aby uruchomić aplikację + Hasło musi mieć co najmniej 4 znaki + Trwale usunąć wszystkie ostatnie zapytania wyszukiwania? + Zapisano kopię zapasową + Systemy niektórych urządzeń inaczej się zachowują. Może to zakłócać wykonywanie zadań w tle. + W kolejce + Pobierz lub przeczytaj ten brakujący rozdział online. + Brak rozdziału + Uprawniony + Logowanie na %s nie jest obsługiwane + Zostaniesz wylogowany ze wszystkich źródeł + Wyklucz mangi NSFW z historii + Wykorzystane źródła + Zablokuj na NSFW + Proponuj mangi na podstawie Twoich preferencji + Wszystkie dane są analizowane tylko lokalnie na tym urządzeniu i nigdy nie są nigdzie wysyłane. + Zacznij czytać mangę, a otrzymasz spersonalizowane sugestie + Nie proponuj mang NSFW + Zresetuj filtr + Ładuj wstępnie strony + Aktualizowanie sugestii + Trwale usunąć wybrane elementy z urządzenia? + Usuwanie zakończone + Pomaga uniknąć blokowania Twojego adresu IP + Przetwarzanie zapisanej mangi + Rozdziały zostaną usunięte w tle + Wpisz swój adres e-mail, aby kontynuować + Dostępne są nowe źródła mang + Sprawdzaj dostępność nowych rozdziałów i informuj o nich + Będziesz otrzymywać powiadomienia o aktualizacjach mang, które czytasz + Nie będziesz otrzymywać powiadomień, ale nowe rozdziały będą podświetlane na listach + Śledzenie + Automatycznie wykryj, czy manga to webtoon + Pomaga w sprawdzaniu aktualizacji w tle + Coś poszło nie tak. Zgłoś błąd programistom, aby pomóc nam go naprawić. + Może pomóc w przypadku niektórych problemów. Wszystkie autoryzacje zostaną unieważnione + Brak źródeł mang + Włącz źródła mang do czytania mang online + Czy na pewno chcesz usunąć wybrane ulubione kategorie\? +\nWszystkie w nich mangi zostaną usunięte i nie będzie można tego cofnąć. + Naciśnij ponownie Wstecz, aby wyjść + Naciśnij dwukrotnie przycisk Wstecz, aby wyjść z aplikacji + Treść nie została znaleziona lub została usunięta + Pokaż pasek informacji w czytniku + Archiwum komiksów + Folder z obrazami + Importowanie mangi + Importowanie zakończone + Możesz usunąć oryginalny plik z pamięci, aby zaoszczędzić miejsce + Import rozpocznie się wkrótce + Wybrane ustawienia kolorów zostaną zapamiętane dla tej mangi + Pokaż ostatnie skróty do mang + Pokaż ostatnie mangi po długim naciśnięciu ikony aplikacji + Stuknięcie w prawą krawędź lub naciśnięcie prawego klawisza zawsze powoduje przejście do następnej strony + Ergonomiczne sterowanie czytnikiem + Zapisać czy odrzucić niezapisane zmiany? + Brak miejsca w urządzeniu + Pokaż suwak przełączania stron + Powiększanie webtoon + Wyczyść też informacje o nowych rozdziałach + Resetuj + Szczegóły błędu:<br><tt>%1$s</tt><br><br>1. Spróbuj <a href=%2$s>otworzyć mangę w przeglądarce internetowej</a>, aby upewnić się, że jest dostępna w swoim źródle<br>2. Upewnij się, że używasz <a href=kotatsu://about>najnowszej wersji Kotatsu</a><br>3. Jeśli jest dostępny, wyślij raport o błędzie do programistów. + Mamimi + Kanade + Usługi + Tutaj nic nie ma + By śledzić postęp w czytaniu, wybierz Menu → Śledź na ekranie detali mangi. + Znajdź podobne + Nagłówek UserAgent + Tłumaczenia + Udostępnij dzienniki + Zapisz niektóre działania do celów debugowania + Zezwól na niestabilne altualizacje + Rozumiem + Uruchom ponownie aplikację by wprowadzić te zmiany + Prędkość + Stuknij i przytrzymaj element, aby zmienić jego kolejność + Możesz wybrać jeden lub więcej plików .cbz lub .zip, każdy plik zostanie rozpoznany jako osobna manga. + Możesz wybrać katalog z archiwami lub obrazami. Każde archiwum (lub podkatalog) zostanie rozpoznane jako rozdział. + Włączać + Wstępne ładowanie treści + Oznacz jako aktualne + Włącz logowanie + Pokaż podejrzane treści + Schemat kolorów + Pokaż w widoku siatki + Miku + Dynamiczne + Asuka + Rikka + Sakura + Mion + Ignoruj błędy SSL + Wybierz lustro automatycznie + Zaimportuj utworzoną wcześniej kopię zapasową danych użytkownika + Pokaż na półce + Automatycznie przełączaj domeny dla zdalnych źródeł w przypadku błędów, jeśli dostępne są kopie lustrzane + Pauza + Wznawiać + Wstrzymane + Anulować całość + Pobieraj tylko przez Wi-Fi + Zatrzymaj pobieranie po przełączeniu na sieć komórkową + Sugestia: %s + Czasami wyświetlaj powiadomienia z sugerowaną mangą + Więcej + Nie, dziękuję + Wszystkie aktywne pobrania zostaną anulowane, częściowo pobrane dane zostaną utracone + Usuwanie zakończone + Język + Zaproponuj aktualizacje do wersji beta aplikacji + Pobieranie rozpoczęte + Ustawienia synchronizacji + Adres serwera + Możesz użyć samoobsługowego serwera synchronizacji lub serwera domyślnego. Nie zmieniaj tego, jeśli nie jesteś pewien, co robisz. + Twoja historia pobrań zostanie trwale usunięta + Nie masz żadnych pobrań + Pobieranie zostało wstrzymane + Pobieranie zostało wznowione + Pobieranie zostało anulowane + Pliki do pobrania zostały usunięte + Czy chcesz otrzymywać spersonalizowane sugestie dotyczące mangi\? + WebView niedostępny: sprawdź, czy dostawca WebView jest zainstalowany + Wyczyść pamięć podręczną sieci + Typ + Adres + Port + Proxy + Możesz zalogować się na istniejące konto lub utworzyć nowe + \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 3ce28e5c0..ff3015e29 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -412,4 +412,11 @@ Хотите ли Вы получать персонализированные рекомендации манги\? Переводы WebView недоступен: проверьте, установлен ли провайдер WebView + Очистить сетевой кеш + Адрес + Тип + Прокси + Порт + %1$s (%2$s) + Неверное значение \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 0304f772b..c9ab878da 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -412,4 +412,11 @@ Хочете отримувати персоналізовані пропозиції щодо манги\? WebView недоступний: перевірте, чи встановлено провайдер WebView Переклади + Очистити мережевий кеш + Порт + Проксі + Тип + Адреса + %1$s (%2$s) + Недійсне значення \ No newline at end of file From f44db3dbff0a24bf97fb3fc193f1f45eadaf50ae Mon Sep 17 00:00:00 2001 From: Reza Almanda Date: Sun, 4 Jun 2023 12:57:06 +0200 Subject: [PATCH 66/94] Translated using Weblate (Indonesian) Currently translated at 100.0% (421 of 421 strings) Co-authored-by: Reza Almanda Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/ Translation: Kotatsu/Strings --- app/src/main/res/values-in/strings.xml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index bd3346c8a..7cda7bcce 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -1,6 +1,6 @@ - Lokal + Penyimpanan lokal Favorit Riwayat Terjadi kesalahan @@ -160,7 +160,7 @@ Selalu blokir Saran Aktifkan saran - Sarankan komik berdasarkan preferensi Anda + Sarankan manga berdasarkan preferensi Anda Semua data hanya dianalisis secara lokal pada perangkat ini dan tidak pernah dikirim ke mana pun. Mulai membaca komik dan Anda akan mendapatkan saran yang dipersonalisasi Jangan menyarankan komik NSFW @@ -296,7 +296,7 @@ Folder dengan gambar Anda bisa menghapus berkas asli dari penyimpanan untuk menghemat ruang Umpan - Detail kesalahan:<br><tt>%1$s</tt><br><br>1. Coba <a href=%2$s>buka komik di browser</a> untuk memastikan komik tersedia di sumbernya<br>2. Pastikan Anda menggunakan <a href=kotatsu://about>Kotatsu versi terbaru</a><br>3. Jika tersedia, kirim laporan kesalahan ke pengembang. + Rincian error:<tt>%1$s</tt><br><br>1. Coba <a href=%2$s>buka manga di peramban web</a> untuk memastikan manga tersebut tersedia di sumbernya</a>2. Pastikan Anda menggunakan <a href= >manga versi terbaru</a><br>3. Jika tersedia, kirimkan laporan kesalahan ke pengembang. Pastikan Anda menggunakan <a href=kotatsu://about>versi terbaru Kotatsu</a><br>3. Jika tersedia, kirimkan laporan kesalahan ke pengembang. Kecerahan Kontras Atur Ulang @@ -375,12 +375,12 @@ Zoom webtoon Berbagai bahasa Jaringan tidak tersedia - Mengerti + Oke Ketuk dan tahan item untuk menyusun ulang Anda dapat memilih satu atau beberapa file .cbz atau .zip, setiap file akan dikenali sebagai komik terpisah. Anda dapat memilih direktori yang berisi arsip atau gambar. Setiap arsip (atau subdirektori) akan dikenali sebagai sebuah bab. Kecepatan - Impor cadangan data pengguna yang dibuat sebelumnya + Impor cadangan data pengguna yang telah dibuat sebelumnya Tampilkan di Rak Anda dapat masuk ke akun yang sudah ada atau membuat akun baru Temukan serupa @@ -401,7 +401,7 @@ Batalkan semua Berhenti mengunduh saat beralih ke jaringan seluler Saran: %s - Terkadang menampilkan notifikasi dengan komik yang disarankan + Terkadang menampilkan notifikasi dengan manga yang disarankan Lebih Semua pengunduhan yang aktif akan dibatalkan, data yang sudah terunduh sebagian akan hilang Riwayat unduhan Anda akan dihapus secara permanen @@ -410,4 +410,11 @@ Unduhan telah dijeda Unduhan telah dihapus Apakah Anda ingin menerima saran manga yang dipersonalisasi\? + Terjemahan + WebView tidak tersedia: periksa apakah penyedia WebView telah diinstal + Hapus cache jaringan + Tipe + Alamat + Port + Proksi \ No newline at end of file From 466e35fffa282ba1f93e44c3344017296f5235e6 Mon Sep 17 00:00:00 2001 From: Clxff H3r4ld0 <123844876+clxf12@users.noreply.github.com> Date: Sun, 4 Jun 2023 12:57:07 +0200 Subject: [PATCH 67/94] Translated using Weblate (Indonesian) Currently translated at 100.0% (430 of 430 strings) Translated using Weblate (Indonesian) Currently translated at 100.0% (423 of 423 strings) Translated using Weblate (Indonesian) Currently translated at 100.0% (422 of 422 strings) Co-authored-by: Clxff H3r4ld0 <123844876+clxf12@users.noreply.github.com> Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/ Translation: Kotatsu/Strings --- app/src/main/res/values-in/strings.xml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 7cda7bcce..cd8f8db8a 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -148,7 +148,7 @@ Anda akan keluar dari semua sumber Genre Selesai - Berlanjut + Sedang berlangsung Standar Kecualikan komik NSFW dari riwayat Nomor halaman @@ -187,7 +187,7 @@ Hapus yang dipilih dari perangkat secara permanen\? Selesai menghapus Perlambat unduhan - Pembaruan saran + Memperbarui saran Membantu menghidari pemblokiran alamat IP Anda Bab akan dihapus di latar belakang Sembunyikan @@ -216,7 +216,7 @@ Kategori favorit Hapus Bersihkan umpan pembaruan - Kanan ke kiri + Kanan-ke-kiri Putar layar Pembaruan umpan akan dimulai Masukkan kata sandi @@ -248,8 +248,8 @@ Pas tinggi Pas lebar Balik - Antri - Diotorisasi + Mengantri + Resmi Simpan dari sumber daring atau berkas impor. Komik Anda akan ditampilkan di sini Cari apa untuk dibaca di bagian «Jelajah» @@ -354,7 +354,7 @@ Tampilkan indikator kemajuan membaca Tampilkan persentase baca dalam riwayat dan favorit Bahasa - Cobalah untuk merubah kueri. + Cobalah untuk memformulasi ulang kueri. Tetap di awal Bab. %1$d/%2$d Hal. %3$d/%4$d Aktifkan pencatatan @@ -417,4 +417,13 @@ Alamat Port Proksi + Nilai tidak valid + %1$s (%2$s) + Gunakan layanan wsrv.nl untuk mengurangi penggunaan lalu lintas dan mempercepat pemuatan gambar jika memungkinkan + Proksi pengoptimalan gambar + NamaUser + Diunduh + Balikkan warna + Kata sandi + Otorisasi (opsional) \ No newline at end of file From 759df969c9ac5f58c1f6831602c8fd1d7917a46e Mon Sep 17 00:00:00 2001 From: wr131 Date: Sun, 4 Jun 2023 12:57:07 +0200 Subject: [PATCH 68/94] Translated using Weblate (Chinese (Traditional)) Currently translated at 23.4% (99 of 422 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 99.2% (419 of 422 strings) Co-authored-by: wr131 Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hant/ Translation: Kotatsu/Strings --- app/src/main/res/values-zh-rCN/strings.xml | 7 +- app/src/main/res/values-zh-rTW/strings.xml | 191 +++++++++++---------- 2 files changed, 108 insertions(+), 90 deletions(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 5b20c9e2a..6ca5165d3 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -407,9 +407,14 @@ 下载被取消 你想要接收个人漫画推荐吗? 推荐:%s - 偶尔对建议的漫画显示通知 + 偶尔显示建议漫画通知 更多 所有进行中的下载都将被取消,未下载完成的数据将丢失 你的下载历史将会永久删除 你可以登陆一个已有账号或创建新账号 + 地址 + 清除网络缓存 + 代理 + 类型 + 无效值 \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 9d6ec4c85..830fe30b2 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1,91 +1,104 @@ - 你将不会收到通知,但新的章节将在列表中突出显示 - 计算… - 再试一次 - 尚无历史记录 - 不支持这种操作 - 在 \"探索 \"部分找到要读的内容 - 从在线来源保存或导入文件。 - 你所读的内容将在这里显示 - 在侧面菜单中找到要读的内容。 - 你的漫画将显示在这里 - 这里有点空… - 饲料更新将很快开始 - 所选择的配置将因这部漫画而被记住 - 数据被恢复了,但有错误 - 在AMOLED屏幕上使用更少的电力 - 登录后可查看此内容 - 永久地删除所有最近的搜索查询? - 永久地清除所有的更新历史? - 你将从所有来源中注销 - 從歷史中排除NSFW漫畫 - 开始阅读漫画,你会得到个性化的建议 - 根据你的喜好推荐漫画 - 指定您不希望在建议中看到的体裁 - 从设备中永久删除选定的项目? - 无法加载流派列表 - 章节将在后台被删除。这可能需要一些时间 - 检查新的章节并通知有关情况 - 有助于避免阻断你的IP地址 - 输入你的电子邮件以继续 - 有了新的漫画来源 - 自动检测漫画是否为网络漫画 - 在历史和收藏夹中显示阅读百分比 - 再次按 \"返回 \"键退出 - 本地存储 - 轻敲右边缘或按右键总是切换到下一页 - 你有未保存的修改,你想保存还是丢弃它们? - 您可以從儲存中刪除原始檔案以節省空間 - 最爱 - 章节 - 列表 - 栅格 - 设置 - 没有发现 - 选择你想看的漫画的语言。你可以在以后的设置中改变它。 - 可以在出现一些问题时提供帮助。所有授权将被视为无效 - 历史 - 发生了一个错误 - 无法连接到互联网 - 详情 - 第%1$d 。%2$d - 详细列表 - 列表模式 - 远程资源 - 正在加载… - 关闭 - 清除历史 - 所有的数据都在这个设备上进行本地分析。您的个人数据不会被转移到任何服务机构。 - 标记为NSFW的漫画将永远不会被添加到历史中,你的进度也不会被保存 - 你可以创建你的历史和收藏的备份并恢复它 - 出了点问题。请向开发人员提交一份错误报告,以帮助我们修复它。 - 所选择的颜色设置将被铭记在这部漫画中 - 要么选择ZIP或CBZ文件。 - 你可以在阅读漫画时创建书签 - 你会收到你正在阅读的漫画的更新通知 - 一些设备有不同的系统行为,这可能会破坏后台任务。 - 输入密码以启动应用程序 - 下载或在线阅读这缺失的章节。 - 在启动Kotatsu时要求输入密码 - 这部漫画中没有章节 - 你正在阅读的新章节显示在这里 - 通过长按应用程序图标来提供最近的漫画 - 这部漫画有%s 。全部保存? - 新版本的应用程序已经推出 - 密码必须是4个字符或以上 - 不支持在%s 上登录 - \"%s\" 从本地存储中删除 - 按两次 \"返回 \"键,退出应用程序 - 启用漫画来源,在线阅读漫画 - 永久清除所有阅读历史? - 从设备中永久删除 \"%s\"? - 尝试重新表述查询。 - 帮助进行背景更新检查 - 请勿推荐NSFW漫画 - 新类别 - 阅读 - 暂时没有喜欢的人 - 最喜欢这个 - 添加 - + 你将不会收到通知,但新的章节将在列表中突出显示 + 计算… + 再试一次 + 尚无历史记录 + 不支持这种操作 + 在 \"探索 \"部分找到要读的内容 + 从在线来源保存或导入文件。 + 你所读的内容将在这里显示 + 在侧面菜单中找到要读的内容。 + 你的漫画将显示在这里 + 这里有点空… + 饲料更新将很快开始 + 所选择的配置将因这部漫画而被记住 + 数据被恢复了,但有错误 + 在AMOLED屏幕上使用更少的电力 + 登录后可查看此内容 + 永久地删除所有最近的搜索查询? + 永久地清除所有的更新历史? + 你将从所有来源中注销 + 從歷史中排除NSFW漫畫 + 开始阅读漫画,你会得到个性化的建议 + 根据你的喜好推荐漫画 + 指定您不希望在建议中看到的体裁 + 从设备中永久删除选定的项目? + 无法加载流派列表 + 章节将在后台被删除。这可能需要一些时间 + 检查新的章节并通知有关情况 + 有助于避免阻断你的IP地址 + 输入你的电子邮件以继续 + 有了新的漫画来源 + 自动检测漫画是否为网络漫画 + 在历史和收藏夹中显示阅读百分比 + 再次按 \"返回 \"键退出 + 本地存储 + 轻敲右边缘或按右键总是切换到下一页 + 你有未保存的修改,你想保存还是丢弃它们? + 您可以從儲存中刪除原始檔案以節省空間 + 最爱 + 章节 + 列表 + 栅格 + 设置 + 没有发现 + 选择你想看的漫画的语言。你可以在以后的设置中改变它。 + 可以在出现一些问题时提供帮助。所有授权将被视为无效 + 历史 + 发生了一个错误 + 无法连接到互联网 + 详情 + 第%1$d 。%2$d + 详细列表 + 列表模式 + 远程资源 + 正在加载… + 关闭 + 清除历史 + 所有的数据都在这个设备上进行本地分析。您的个人数据不会被转移到任何服务机构。 + 标记为NSFW的漫画将永远不会被添加到历史中,你的进度也不会被保存 + 你可以创建你的历史和收藏的备份并恢复它 + 出了点问题。请向开发人员提交一份错误报告,以帮助我们修复它。 + 所选择的颜色设置将被铭记在这部漫画中 + 要么选择ZIP或CBZ文件。 + 你可以在阅读漫画时创建书签 + 你会收到你正在阅读的漫画的更新通知 + 一些设备有不同的系统行为,这可能会破坏后台任务。 + 输入密码以启动应用程序 + 下载或在线阅读这缺失的章节。 + 在启动Kotatsu时要求输入密码 + 这部漫画中没有章节 + 你正在阅读的新章节显示在这里 + 通过长按应用程序图标来提供最近的漫画 + 这部漫画有%s 。全部保存? + 新版本的应用程序已经推出 + 密码必须是4个字符或以上 + 不支持在%s 上登录 + \"%s\" 从本地存储中删除 + 按两次 \"返回 \"键,退出应用程序 + 启用漫画来源,在线阅读漫画 + 永久清除所有阅读历史? + 从设备中永久删除 \"%s\"? + 尝试重新表述查询。 + 帮助进行背景更新检查 + 请勿推荐NSFW漫画 + 新类别 + 阅读 + 暂时没有喜欢的人 + 最喜欢这个 + 添加 + 存儲 + 分享 %s + 搜尋 + 下載中…… + 已下載 + 過濾器 + 主題 + 淺色 + 清除 + 刪除 + 分享圖片 + 刪除 + 清除頁面快取 + \ No newline at end of file From 73217b8e11b6968145298ddf0b6905ee1d70b8c5 Mon Sep 17 00:00:00 2001 From: FateXBlood Date: Sun, 4 Jun 2023 12:57:08 +0200 Subject: [PATCH 69/94] Translated using Weblate (Nepali) Currently translated at 34.1% (144 of 422 strings) Co-authored-by: FateXBlood Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ne/ Translation: Kotatsu/Strings --- app/src/main/res/values-ne/strings.xml | 193 ++++++++++++++++++------- 1 file changed, 141 insertions(+), 52 deletions(-) diff --git a/app/src/main/res/values-ne/strings.xml b/app/src/main/res/values-ne/strings.xml index 9d72ad6df..446981da9 100644 --- a/app/src/main/res/values-ne/strings.xml +++ b/app/src/main/res/values-ne/strings.xml @@ -1,53 +1,142 @@ - - डाउनलोड गर्दै… - डाउनलोड गरेको - फिल्टर - अँध्यारो - खाली गर्नुहोस् - पृष्ठहरू - एउटा त्रुटि भयो - सूची मोड - सूची - पुनः प्रयास गर्नुहोस् - केही पनि फेला परेन - पढ्नुहोस् - लोकल भण्डारण - इतिहास - नेटवर्क त्रुटि - अध्यायहरू - सेटिङहरू - रिमोट स्रोतहरू - लोड हुँदै… - इतिहास खाली गर्नुहोस् - अहिले कुनै मनपर्ने छैन - मनपर्ने मा राख्नुहोस् - नयाँ वर्ग - %s साझा गर्नुहोस् - खोज्नुहोस् - माङ्गा खोज्नुहोस् - प्रक्रिया गर्दैछ… - डाउनलोडहरू - नाम - अपडेट गरियो - नवीनतम - क्रमबद्ध क्रम - थीम - उज्यालो - सिस्टम पालना गर्नुहोस् - कम्प्युटिङ… - मनपर्नेहरू - विवरणहरू - विस्तृत सूची - ग्रिड - %2$d को अध्याय %1$d - बन्द गर्नुहोस् - अहिलेसम्म इतिहास छैन - थप्नुहोस् - बचत गर्नुहोस् - साझा गर्नुहोस् - सर्टकट सिर्जना गर्नुहोस्… - लोकप्रिय - मूल्याङ्कन - नयाँ अध्यायहरू - + + डाउनलोड गर्दै… + डाउनलोड गरेको + फिल्टर + अँध्यारो + खाली गर्नुहोस् + पृष्ठहरू + एउटा त्रुटि भयो + सूची मोड + सूची + पुनः प्रयास गर्नुहोस् + केही पनि फेला परेन + पढ्नुहोस् + लोकल भण्डारण + इतिहास + नेटवर्क त्रुटि + अध्यायहरू + सेटिङहरू + माङ्गा स्रोतहरू + लोड हुँदै… + इतिहास खाली गर्नुहोस् + अहिले कुनै मनपर्ने छैन + मनपर्ने मा राख्नुहोस् + नयाँ वर्ग + %s साझा गर्नुहोस् + खोज्नुहोस् + माङ्गा खोज्नुहोस् + प्रक्रिया गर्दैछ… + डाउनलोडहरू + नाम + अपडेट गरिएको + नवीनतम + क्रमबद्ध क्रम + थीम + उज्यालो + सिस्टम पालना गर्नुहोस् + कम्प्युटिङ… + मनपर्नेहरू + विवरणहरू + विस्तृत सूची + ग्रिड + %2$d को अध्याय %1$d + बन्द गर्नुहोस् + अहिलेसम्म इतिहास छैन + थप्नुहोस् + बचत गर्नुहोस् + साझा गर्नुहोस् + सर्टकट सिर्जना गर्नुहोस्… + लोकप्रिय + मूल्याङ्कन + नयाँ अध्यायहरू + सबै पढेको इतिहास स्थायी रूपमा खाली गर्ने हो\? + हटाउनुहोस् + लोकल भण्डारणबाट %s हटाइयो + सेभ गरियो + पृष्ठ सेभ गर्नुहोस् + छवि साझा गर्नुहोस् + आयात गर्नुहोस् + स्ट्यानडर्ड + वेबटून + पढ्ने मोड + ग्रिड साइज + यन्त्रबाट %s स्थायी रूपमा हटाउने हो\? + रिडर सेटिङहरू + %s मा खोज्नुहोस् + माङ्गा हटाउनुहोस् + पृष्ठ स्विच गर्नुहोस् + किनारा ट्यापहरू + भोल्युम बटन + जारी राख्नुहोस् + त्रुटि + खाली गरियो + जेस्चर मात्र + थम्बनेल क्यास खाली गर्नुहोस् + खोज इतिहास खाली गर्नुहोस् + डोमेन + यो माङ्गामा %s छ। यो सबै सेभ गर्ने\? + आन्तरिक भण्डारण + एपको नयाँ संस्करण उपलब्ध छ + बाह्य भण्डारण + वेब ब्राउजरमा खोल्नुहोस् + डाउनलोड + सूचना सेटिङ + LED सूचक + भाईब्रेशन + मनपर्ने वर्गहरू + हटाउनुहोस् + यहाँ अलि खाली जस्तो छ… + सोधपुछ सुधार गर्ने प्रयास गर्नुहोस्। + तपाईँले पढेको कुरा यहाँ देखाइनेछ + साइड मेनुमा के पढ्ने फेला पार्नुहोस्। + पृष्ठ एनिमेसन + डाउनलोडका लागि फोल्डर + हालैका + उपलब्ध छैन + तपाईंले पढिरहनु भएको माङ्गाको नयाँ अध्यायहरू यहाँ देखाइएको छ + खोज परिणामहरू + अपडेट फिड खाली गर्नुहोस् + स्क्रिन घुमाउनुहोस् + अपडेट + पासवर्डहरू म्याच गरेनन् + बारेमा + संस्करण %s + यो अपरेशन समर्थित छैन + कुनै विवरण छैन + इतिहास र क्यास + पृष्ठ क्यास खाली गर्नुहोस् + सूचना आवाज + पहिले केही सेभ गर्नुहोस् + यसलाई अनलाइन स्रोतहरूबाट सेभ गर्नुहोस् वा फाइलहरू आयात गर्नुहोस्। + खाली गरियो + एप सुरक्षित गर्नुहोस् + Kotatsu सुरु गर्दा पासवर्ड माग्नुहोस् + पासवर्ड दोहोर्याउनुहोस् + हटाउनुहोस् + या त ZIP वा CBZ फाइल छान्नुहोस्। + B|kB|MB|GB|TB + सेभ + सूचनाहरू + %2$d को %1$d अन + तपाईंको माङ्गा यहाँ देखाउनेछ + «अन्वेषण» भागमा के पढ्ने फेला पार्नुहोस् + दराज + भण्डारण उपलब्ध छैन + अन्य भण्डारण + सकियो + सबै मनपर्नेहरू + खाली वर्ग + पछि पढ्ने + अपडेटहरू + नयाँ संस्करण: %s + साइज: %s + फिड अपडेट चाँडै सुरु हुनेछ + अपडेटहरू खोज्नुहोस् + जाँच नगर्नुहोस् + गलत पासवर्ड + अपडेटका लागि जाँच गर्नुहोस् + कुनै अपडेट उपलब्ध छैन + अन्वेषण + पासवर्ड एन्टर गर्नुहोस् + \ No newline at end of file From 2f1b74e45a876b5cf54eba250c06bff6193ca0fb Mon Sep 17 00:00:00 2001 From: frablock Date: Sun, 4 Jun 2023 12:57:08 +0200 Subject: [PATCH 70/94] Translated using Weblate (French) Currently translated at 100.0% (7 of 7 strings) Translated using Weblate (French) Currently translated at 100.0% (430 of 430 strings) Co-authored-by: frablock Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/fr/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/ Translation: Kotatsu/Strings Translation: Kotatsu/plurals --- app/src/main/res/values-fr/plurals.xml | 65 ++++++++++++++------------ app/src/main/res/values-fr/strings.xml | 9 ++++ 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/app/src/main/res/values-fr/plurals.xml b/app/src/main/res/values-fr/plurals.xml index 31a0ce3e8..c0da2ac13 100644 --- a/app/src/main/res/values-fr/plurals.xml +++ b/app/src/main/res/values-fr/plurals.xml @@ -1,31 +1,38 @@ - - Il y a %1$d minute - Il y a %1$d minutes - - - %1$d page au total - %1$d pages au total - - - %1$d élément - %1$d éléments - - - %1$d nouveau chapitre - %1$d nouveaux chapitres - - - %1$d chapitre - %1$d chapitres - - - Il y a %1$d heure - Il y a %1$d heures - - - Il y a %1$d jour - Il y a %1$d jours - - + + Il y a %1$d minute + Il y a %1$d minutes + Il y a %1$d minutes + + + %1$d page au total + %1$d pages au total + %1$d pages au total + + + %1$d élément + %1$d éléments + %1$d éléments + + + %1$d nouveau chapitre + %1$d nouveaux chapitres + %1$d nouveaux chapitres + + + %1$d chapitre + %1$d chapitres + %1$d chapitres + + + Il y a %1$d heure + Il y a %1$d heures + Il y a %1$d heures + + + Il y a %1$d jour + Il y a %1$d jours + Il y a %1$d jours + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index cd7193ee6..04f0ee800 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -417,4 +417,13 @@ Adresse Port Proxy + Téléchargé + Pseudonyme + Proxy d\'optimisation des images + Inverser les couleurs + Utilisez le service wsrv.nl pour réduire le trafic et augmenter la vitesse de chargement des images si possible + %1$s (%2$s) + Mot de passe + Valeur invalide + Autorisation (optionnel) \ No newline at end of file From bd8b2519345c1f3a22654e4094fea6851aaca61e Mon Sep 17 00:00:00 2001 From: GpixeL Date: Sun, 4 Jun 2023 12:57:08 +0200 Subject: [PATCH 71/94] Translated using Weblate (Indonesian) Currently translated at 100.0% (430 of 430 strings) Co-authored-by: GpixeL Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/ Translation: Kotatsu/Strings --- app/src/main/res/values-in/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index cd8f8db8a..de4eb06bd 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -131,7 +131,7 @@ Selesaikan Bersihkan kuki Semua kuki telah dihapus - Bersihkan umpan + Bersihkan aliran Periksa bab baru Masuk untuk melihat konten ini Selanjutnya @@ -215,10 +215,10 @@ Getaran Kategori favorit Hapus - Bersihkan umpan pembaruan + Bersihkan aliran pembaruan Kanan-ke-kiri Putar layar - Pembaruan umpan akan dimulai + Pembaruan aliran akan dimulai Masukkan kata sandi Tanya kata sandi ketika memulai Kotatsu Tentang From 8d15691e17dc0e31c68122ea1c58013450d9cc0e Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 5 Jun 2023 13:04:26 +0300 Subject: [PATCH 72/94] Remove unused resources --- .weblate | 3 + app/src/main/res/drawable/ic_list_create.xml | 12 - .../res/layout/layout_synchronization.xml | 59 -- app/src/main/res/menu/opt_categories_bs.xml | 12 - app/src/main/res/values-ar/plurals.xml | 42 +- app/src/main/res/values-ar/strings.xml | 151 ++-- app/src/main/res/values-be/plurals.xml | 5 - app/src/main/res/values-be/strings.xml | 834 +++++++++-------- app/src/main/res/values-bn/plurals.xml | 22 +- app/src/main/res/values-de/plurals.xml | 54 +- app/src/main/res/values-de/strings.xml | 820 +++++++++-------- app/src/main/res/values-el/plurals.xml | 4 - app/src/main/res/values-el/strings.xml | 1 - app/src/main/res/values-es/plurals.xml | 67 +- app/src/main/res/values-es/strings.xml | 848 +++++++++--------- app/src/main/res/values-fi/strings.xml | 4 - app/src/main/res/values-fil/plurals.xml | 4 - app/src/main/res/values-fil/strings.xml | 820 +++++++++-------- app/src/main/res/values-fr/plurals.xml | 67 +- app/src/main/res/values-fr/strings.xml | 848 +++++++++--------- app/src/main/res/values-hi/plurals.xml | 4 - app/src/main/res/values-in/plurals.xml | 3 - app/src/main/res/values-in/strings.xml | 848 +++++++++--------- app/src/main/res/values-it/plurals.xml | 4 - app/src/main/res/values-it/strings.xml | 4 - app/src/main/res/values-ja/plurals.xml | 3 - app/src/main/res/values-ja/strings.xml | 848 +++++++++--------- app/src/main/res/values-kk/strings.xml | 1 - app/src/main/res/values-ko/strings.xml | 4 - app/src/main/res/values-nb-rNO/plurals.xml | 4 - app/src/main/res/values-nb-rNO/strings.xml | 4 - app/src/main/res/values-ne/plurals.xml | 4 - app/src/main/res/values-ne/strings.xml | 279 +++--- app/src/main/res/values-nn/plurals.xml | 4 - app/src/main/res/values-nn/strings.xml | 714 ++++++++------- app/src/main/res/values-or/plurals.xml | 46 +- app/src/main/res/values-or/strings.xml | 53 +- app/src/main/res/values-pl/plurals.xml | 5 - app/src/main/res/values-pl/strings.xml | 830 +++++++++-------- app/src/main/res/values-pt-rBR/plurals.xml | 4 - app/src/main/res/values-pt-rBR/strings.xml | 4 - app/src/main/res/values-pt/strings.xml | 4 - app/src/main/res/values-ru/plurals.xml | 5 - app/src/main/res/values-ru/strings.xml | 834 +++++++++-------- app/src/main/res/values-sr/plurals.xml | 5 - app/src/main/res/values-sv/plurals.xml | 4 - app/src/main/res/values-sv/strings.xml | 4 - app/src/main/res/values-tr/plurals.xml | 4 - app/src/main/res/values-tr/strings.xml | 834 +++++++++-------- app/src/main/res/values-uk/plurals.xml | 6 - app/src/main/res/values-uk/strings.xml | 834 +++++++++-------- app/src/main/res/values-vi/plurals.xml | 3 - app/src/main/res/values-zh-rCN/plurals.xml | 3 - app/src/main/res/values-zh-rCN/strings.xml | 830 +++++++++-------- app/src/main/res/values-zh-rTW/strings.xml | 203 +++-- app/src/main/res/values/plurals.xml | 4 - app/src/main/res/values/strings.xml | 4 - app/src/main/res/values/styles.xml | 4 - app/src/main/res/values/themes.xml | 8 - 59 files changed, 5823 insertions(+), 6117 deletions(-) create mode 100644 .weblate delete mode 100644 app/src/main/res/drawable/ic_list_create.xml delete mode 100644 app/src/main/res/layout/layout_synchronization.xml delete mode 100644 app/src/main/res/menu/opt_categories_bs.xml diff --git a/.weblate b/.weblate new file mode 100644 index 000000000..4a120e1a3 --- /dev/null +++ b/.weblate @@ -0,0 +1,3 @@ +[weblate] +url = https://hosted.weblate.org/api/ +translation = kotatsu/strings diff --git a/app/src/main/res/drawable/ic_list_create.xml b/app/src/main/res/drawable/ic_list_create.xml deleted file mode 100644 index dce66429c..000000000 --- a/app/src/main/res/drawable/ic_list_create.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/layout_synchronization.xml b/app/src/main/res/layout/layout_synchronization.xml deleted file mode 100644 index d9d728fbe..000000000 --- a/app/src/main/res/layout/layout_synchronization.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/menu/opt_categories_bs.xml b/app/src/main/res/menu/opt_categories_bs.xml deleted file mode 100644 index 2e5f4ad73..000000000 --- a/app/src/main/res/menu/opt_categories_bs.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - diff --git a/app/src/main/res/values-ar/plurals.xml b/app/src/main/res/values-ar/plurals.xml index 46a1c60eb..0145329ea 100644 --- a/app/src/main/res/values-ar/plurals.xml +++ b/app/src/main/res/values-ar/plurals.xml @@ -1,27 +1,19 @@ - - %1$d فصل جديد - - - - %1$d فصول جديدة - - - - - %1$d فصل - %1$d فصلين - %1$d بعض فصول - %1$d عدة فصول - - - - - مجموع %1$d فصل - مجموع %1$d فصلين - مجموع %1$d بعض فصول - مجموع %1$d عدة فصول - مجموع %1$d فصول اخرى - - \ No newline at end of file + + %1$d فصل جديد + + + + %1$d فصول جديدة + + + + + %1$d فصل + %1$d فصلين + %1$d بعض فصول + %1$d عدة فصول + + + diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 63bfe975b..829137c78 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -1,78 +1,77 @@ - تفاصيل القائمة - حدث خطأ - تفاصيل - شبكة - وضع القائمة - إعدادات - المصادر البعيدة - فصول - المفضلة - ‌خطاء في الشبكة - جار التحميل… - فصل %1$d في %2$d - غلق - حاول مجدداً - جاري الحوسبة … - التخزين المحلي - سجل - قائمة - محو سجل - ضع هذا في المفضلة - أضف - حفظ - لا سجل بعد - التحميلات - اسم - الأحدث - تقييم - صفحات - اقرأ - شارك - لم يتم عثور على اي شيء - لا مفضلة بعد - بحث - البحث في المانجا - جاري التنزيل… - انشاء اختصار… - مظهر - حسب النظام - شارك %s - في طور معالجة… - محدث - فلتر - ترتيب الفرز - ضوء - داكن - أزل - ازالة - شائع - قائمة جديدة - تم التنزيل - هل تريد محو سجل القراءة بالكامل بشكل دائم؟ - احفظ الصفحة - حفظت - اساسي - لا يوجد وصف - التاريخ وذاكرة التخزين المؤقت - مسح ذاكرة التخزين المؤقت للصفحة - ويبتون - وضع القراءة - بحث على %s - حذف المانغا - حذف \"%s\" من الجهاز نهائيا؟ - إعدادات القراءة - تغییر صفحات - حذف - شارك الصورة - إما أن تختار ملف ZIP أو CBZ. - استورد - هذا خيار غير مدعم - حجم الشبكة - أزرار الصوت - النقر على حواف الشاشة - يكمل - خطاء - مسح تاريخ البحث - \ No newline at end of file + تفاصيل القائمة + حدث خطأ + تفاصيل + شبكة + وضع القائمة + إعدادات + المصادر البعيدة + فصول + المفضلة + ‌خطاء في الشبكة + جار التحميل… + فصل %1$d في %2$d + غلق + حاول مجدداً + جاري الحوسبة … + التخزين المحلي + سجل + قائمة + محو سجل + ضع هذا في المفضلة + أضف + حفظ + لا سجل بعد + التحميلات + اسم + الأحدث + تقييم + صفحات + اقرأ + شارك + لم يتم عثور على اي شيء + لا مفضلة بعد + بحث + البحث في المانجا + جاري التنزيل… + انشاء اختصار… + مظهر + حسب النظام + شارك %s + في طور معالجة… + محدث + فلتر + ترتيب الفرز + ضوء + داكن + أزل + ازالة + شائع + قائمة جديدة + تم التنزيل + هل تريد محو سجل القراءة بالكامل بشكل دائم؟ + احفظ الصفحة + حفظت + اساسي + لا يوجد وصف + مسح ذاكرة التخزين المؤقت للصفحة + ويبتون + وضع القراءة + بحث على %s + حذف المانغا + حذف \"%s\" من الجهاز نهائيا؟ + إعدادات القراءة + تغییر صفحات + حذف + شارك الصورة + إما أن تختار ملف ZIP أو CBZ. + استورد + هذا خيار غير مدعم + حجم الشبكة + أزرار الصوت + النقر على حواف الشاشة + يكمل + خطاء + مسح تاريخ البحث + diff --git a/app/src/main/res/values-be/plurals.xml b/app/src/main/res/values-be/plurals.xml index 79edd9584..e27eb524b 100644 --- a/app/src/main/res/values-be/plurals.xml +++ b/app/src/main/res/values-be/plurals.xml @@ -1,10 +1,5 @@ - - Усяго %1$d старонка - Усяго %1$d старонкі - Усяго %1$d старонак - %1$d элемент %1$d элементы diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index 63229ce62..c6f21aae2 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -1,422 +1,418 @@ - На прыладзе - Абраныя - Гісторыя - Адбылася памылка - Памылка сеткі - Падрабязнасцi - Раздзелы - Спіс - Падрабязны спіс - Табліца - Выгляд спісу - Налады - Крыніцы мангі - Загрузка… - Глава %1$d з %2$d - Закрыць - Паўтарыць - Ачысціць гісторыю - Нічога не знойдзена - Гісторыя пустая - Чытаць - Дадайце цікавую для вас мангу ў абранае, каб не страціць яе - Дадаць у абраныя - Стварыць катэгорыю - Дадаць - Захаваць - Падзяліцца - Стварыць ярлык… - Падзялiцца %s - Пошук - Пошук мангі - Спампоўванне мангі… - Апрацоўка… - Спампоўванне завершана - Спампоўкі - Па імю - Папулярная - Абноўленая - Новая - Па рэйтынгу - Сартаванне - Фільтр - Тэма - Светлая - Цёмная - Як у сістэме - Старонкi - Ачысціць - Вы ўпэўненыя, што жадаеце ачысціць гісторыю\? - Выдаліць - «%s» выдалена з прылады - Захаваць старонку - Старонка захавана - Падзяліцца выявай - Імпарт - Выдаліць - Аперацыя не падтрымліваецца - Файл не падтрымліваецца. Падтрымліваюцца толькі ZIP і CBZ. - Няма апісання - Гісторыя і кэш - Ачысціць кэш старонак - Б|кБ|МБ|ГБ|ТБ - Стандартны - Манхва - Рэжым чытання - Памер табліцы - Пошук па %s - Выдаліць мангу - Налады чытання - Гартанне старонак - Вы ўпэўненыя, што жадаеце выдаліць «%s» з прылады\? - Націск па краях - Кнопкі гучнасці - Працягнцуць - Памылка - Ачысціць кэш мініяцюр - Гісторыя пошуку ачышчана - Ачысціць гісторыю пошуку - Толькі жэсты - Унутранае сховішча - Знешняе сховішча - Дамен - Даступна абнаўленне праграмы - Адкрыць у браўзеры - У гэтай манге %s. Вы ўпэўненыя, што хочаце захаваць іх усё\? - Захаваць мангу - Паведамленні - Уключана %1$d з %2$d - Новыя раздзелы - Спампаваць - Налады апавяшчэнняў - Гук апавяшчэння - Светлавая iндыкацыя - Вібрацыя - Катэгорыі абранага - Выдаліць катэгорыю - Паліца з мангай - Нядаўняя манга - Анімацыя гартання - Месца спампоўвання мангі - Недаступна - Не атрымалася знайсці ніводнага даступнага сховішча - Іншае сховішча - Гатова - Усе абраныя - У гэтай катэгорыі нічога няма - Прачытаць пазней - Абнаўленні - Тут будуць паказвацца абнаўлення мангі, якую вы чытаеце - Вынікі пошуку - Новая версія: %s - Памер: %s - Ачысціць стужку абнаўленняў - Стужка абнаўленняў ачышчана - Павярнуць экран - Абнавіць - Абнаўленне хутка пачнецца - Правяраць абнаўленні мангі - Не правяраць - Увядзіце пароль - Няверны пароль - Абараніць праграму - Запытваць пароль пры запуску праграмы - Паўтарыце пароль - Паролі не супадаюць - Аб праграме - Версія %s - Праверыць абнаўленні - Няма даступных абнаўленняў - Справа налева - Стварыць катэгорыю - Маштабаванне - Умясціць у экран - Падагнаць па вышыні - Падагнаць па шырыні - Зыходны памер - Чорная - Спажывае менш энергіі на экранах AMOLED - Рэзервовае капіяванне і аднаўленне - Стварыць рэзервовую копію - Аднавіць данныя - Данныя адноўлены - Падрыхтоўка… - Файл не знойдзены - Усе данныя паспяхова адноўлены - Данныя адноўлены, але ўзніклі некаторыя памылкі - Вы можаце стварыць рэзервовую копію абранага і гісторыі і потым аднавіць іх - Толькі што - Учора - Даўно - Групаваць - Сёння - Паспрабаваць яшчэ раз - Абраны рэжым будзе захаваны для бягучай мангі - Без гуку - Неабходна прайсці CAPTCHA - Прайсці - Ачысціць кукi - Усе кукi выдалены - Ачысціць стужку - Уся гісторыя абнаўленняў будзе ачышчана і яе нельга будзе вярнуць. Вы ўпэўненыя\? - Праверка новых глаў - У адваротным парадку - Увайсці - Для прагляду гэтага кантэнту патрабуецца аўтарызацыя - Прадвызначаны: %s - Далей - Калі ласка, увядзіце пароль, які спатрэбіцца пры запуску праграмы - Пацвердзіць - Пароль павінен змяшчаць не менш за 4 сімвалы - Вы сапраўды хочаце выдаліць усе апошнія пошукавыя запыты\? - Падрабязна - Некаторыя вытворцы могуць змяняць паводзіны сістэмы, што можа парушаць выкананне фонавых задач. - Рэзервовая копія паспяхова захавана - Вітаю - Вы можаце захаваць мангу з анлайн-крыніц або імпартаваць з файла. - У вас яшчэ няма ніводнай захаванай мангі - Вы можаце знайсці, што пачытаць, у бакавым меню. - Тут будзе паказана манга, якую вы чытаеце - Паспрабуйце перафармуляваць запыт. - Тут неяк пуста… - Глава адсутнічае - Гэтая глава адсутнічае на вашай прыладзе. Спампуйце ціпрачытайце яе онлайн. - У чарзе - Дапамагчы з перакладам праграмы - Пераклад - Вы выйдзеце з усіх крыніц, у якіх вы аўтарызаваны - Аўтарызацыя на %s не падтрымліваецца - Аўтарызацыя выканана - Жанры - Завершана - Ангоінг - Па змаўчанні - Не паказваць NSFW мангу з гісторыі - Паказваць нумары старонак - Уключаныя крыніцы - Даступныя крыніцы - Вылічэнні… - Дазваляць - Палітыка скрыншотаў - Заўсёды блакуйце - Блок на NSFW - Немагчыма загрузіць спіс жанраў - Непрацаздольны - Уключаны - Не прапануйце мангу NSFW - Пачніце чытаць мангу, і вы атрымаеце персаналізаваныя прапановы - Усе даныя аналізуюцца толькі лакальна на гэтай прыладзе і нікуды не адпраўляюцца. - Прапануеце мангу, заснаваную на вашых перавагах - Уключыць прапановы - Прапанова - Выберыце мову, на якой вы хочаце чытаць мангу. Вы зможаце змяніць гэта пазней. - Скінуць фільтр - Знайсці жанр - Заўсёды - 18+ - Ніколі - Толькі праз Wi-Fi - Вы аўтарызаваны як %s - Папярэдняя загрузка старонак - Розныя мовы - Знайсці главу - %1$s%% - У гэтай манзе няма глаў - Схаваць - Знешні выгляд - Змесціва - Выключыць усё - Выкарыстоўваць адбітак пальца, калі даступна - Манга з абраных - Манга, якую вы нядаўна чыталі - Абнаўленне рэкамендацый - Апрацоўка захаванай мангі - Раздзелы будуць выдалены ў фонавым рэжыме - Правяраць новыя главы і паведамляць пра іх - Вы будзеце атрымліваць апавяшчэнні пра абнаўленні мангі, якую вы чытаеце - Вы не будзеце атрымліваць паведамленні, але новыя главы будуць паказаны ў спісе - Уключыць апавяшчэнні - Закладкі - Закладка выдалена - Закладка дадазена - Выдалена з гісторыі - DNS праз HTTPS - Аўтавызначэнне рэжыму чытання - Аўтаматычна вызначае, ці з’яўляецца манга вэбтунам - Даступныя новыя крыніцы мангі - Запавольванне спампоўкі - Выключыць жанры - Укажыце жанры, якія вы не хочаце бачыць у рэкамендацыях - Выдаліць выбраныя элементы з прылады назаўжды\? - Выдаленне завершана - Дапамагае пазбегнуць блакіроўкі па IP-адрасе - Выдаліць закладку - Рэжым па змаўчанні - Няма абраных катэгорый - Назва - Змяніць - Змяніць катэгорыю - Дадаць закладку - Адмяніць - Адключыць аптымізацыю акумулятара - Дапамагае з фонавай праверкай абнаўленняў - Штосьці пайшло не так. Калі ласка, адпраўце справаздачу пра памылку распрацоўшчыкам, каб дапамагчы нам яе выправіць. - Адправіць - Памылковы дамен - Справаздача - Адсочванне - Завершана - Адкладзена - Кінута - Паказваць індыкатары прагрэсу чытання - Запланавана - Чытаю - Выйсці - Паказваць працэнт прачытанага ў гісторыі і абраных - Выдаленне даных - Паказаць усе - Манга, пазначаная як NSFW, ніколі не будзе дададзеная ў гісторыю і ваш прагрэс не будзе захаваны - Можа дапамагчы з некаторымі праблемам. Усе аўтарызацыі будуць ануляваныя - Змесціва не знойдзена ці выдалена - Перачытваю - Выберыце дыяпазон - Тут нічога няма - Службы - Канадзе - Ачысціць усю гісторыю - Гісторыя ачышчана - Рэжым інкогніта - Вы ўпэўнены, што хочаце выдаліць выбраныя абраныя катэгорыі\? + На прыладзе + Абраныя + Гісторыя + Адбылася памылка + Памылка сеткі + Падрабязнасцi + Раздзелы + Спіс + Падрабязны спіс + Табліца + Выгляд спісу + Налады + Крыніцы мангі + Загрузка… + Глава %1$d з %2$d + Закрыць + Паўтарыць + Ачысціць гісторыю + Нічога не знойдзена + Гісторыя пустая + Чытаць + Дадайце цікавую для вас мангу ў абранае, каб не страціць яе + Дадаць у абраныя + Стварыць катэгорыю + Дадаць + Захаваць + Падзяліцца + Стварыць ярлык… + Падзялiцца %s + Пошук + Пошук мангі + Спампоўванне мангі… + Апрацоўка… + Спампоўванне завершана + Спампоўкі + Па імю + Папулярная + Абноўленая + Новая + Па рэйтынгу + Сартаванне + Фільтр + Тэма + Светлая + Цёмная + Як у сістэме + Старонкi + Ачысціць + Вы ўпэўненыя, што жадаеце ачысціць гісторыю\? + Выдаліць + «%s» выдалена з прылады + Захаваць старонку + Старонка захавана + Падзяліцца выявай + Імпарт + Выдаліць + Аперацыя не падтрымліваецца + Файл не падтрымліваецца. Падтрымліваюцца толькі ZIP і CBZ. + Няма апісання + Ачысціць кэш старонак + Б|кБ|МБ|ГБ|ТБ + Стандартны + Манхва + Рэжым чытання + Памер табліцы + Пошук па %s + Выдаліць мангу + Налады чытання + Гартанне старонак + Вы ўпэўненыя, што жадаеце выдаліць «%s» з прылады\? + Націск па краях + Кнопкі гучнасці + Працягнцуць + Памылка + Ачысціць кэш мініяцюр + Гісторыя пошуку ачышчана + Ачысціць гісторыю пошуку + Толькі жэсты + Унутранае сховішча + Знешняе сховішча + Дамен + Даступна абнаўленне праграмы + Адкрыць у браўзеры + У гэтай манге %s. Вы ўпэўненыя, што хочаце захаваць іх усё\? + Захаваць мангу + Паведамленні + Уключана %1$d з %2$d + Новыя раздзелы + Спампаваць + Налады апавяшчэнняў + Гук апавяшчэння + Светлавая iндыкацыя + Вібрацыя + Катэгорыі абранага + Выдаліць катэгорыю + Паліца з мангай + Нядаўняя манга + Анімацыя гартання + Месца спампоўвання мангі + Недаступна + Не атрымалася знайсці ніводнага даступнага сховішча + Іншае сховішча + Гатова + Усе абраныя + У гэтай катэгорыі нічога няма + Прачытаць пазней + Абнаўленні + Тут будуць паказвацца абнаўлення мангі, якую вы чытаеце + Вынікі пошуку + Новая версія: %s + Памер: %s + Ачысціць стужку абнаўленняў + Стужка абнаўленняў ачышчана + Павярнуць экран + Абнавіць + Абнаўленне хутка пачнецца + Правяраць абнаўленні мангі + Не правяраць + Увядзіце пароль + Няверны пароль + Абараніць праграму + Запытваць пароль пры запуску праграмы + Паўтарыце пароль + Паролі не супадаюць + Аб праграме + Версія %s + Праверыць абнаўленні + Няма даступных абнаўленняў + Справа налева + Стварыць катэгорыю + Маштабаванне + Умясціць у экран + Падагнаць па вышыні + Падагнаць па шырыні + Зыходны памер + Чорная + Спажывае менш энергіі на экранах AMOLED + Рэзервовае капіяванне і аднаўленне + Стварыць рэзервовую копію + Аднавіць данныя + Данныя адноўлены + Падрыхтоўка… + Файл не знойдзены + Усе данныя паспяхова адноўлены + Данныя адноўлены, але ўзніклі некаторыя памылкі + Вы можаце стварыць рэзервовую копію абранага і гісторыі і потым аднавіць іх + Толькі што + Учора + Даўно + Групаваць + Сёння + Паспрабаваць яшчэ раз + Абраны рэжым будзе захаваны для бягучай мангі + Без гуку + Неабходна прайсці CAPTCHA + Прайсці + Ачысціць кукi + Усе кукi выдалены + Ачысціць стужку + Уся гісторыя абнаўленняў будзе ачышчана і яе нельга будзе вярнуць. Вы ўпэўненыя\? + Праверка новых глаў + У адваротным парадку + Увайсці + Для прагляду гэтага кантэнту патрабуецца аўтарызацыя + Прадвызначаны: %s + Далей + Калі ласка, увядзіце пароль, які спатрэбіцца пры запуску праграмы + Пацвердзіць + Пароль павінен змяшчаць не менш за 4 сімвалы + Вы сапраўды хочаце выдаліць усе апошнія пошукавыя запыты\? + Падрабязна + Некаторыя вытворцы могуць змяняць паводзіны сістэмы, што можа парушаць выкананне фонавых задач. + Рэзервовая копія паспяхова захавана + Вітаю + Вы можаце захаваць мангу з анлайн-крыніц або імпартаваць з файла. + У вас яшчэ няма ніводнай захаванай мангі + Вы можаце знайсці, што пачытаць, у бакавым меню. + Тут будзе паказана манга, якую вы чытаеце + Паспрабуйце перафармуляваць запыт. + Тут неяк пуста… + Глава адсутнічае + У чарзе + Дапамагчы з перакладам праграмы + Пераклад + Вы выйдзеце з усіх крыніц, у якіх вы аўтарызаваны + Аўтарызацыя на %s не падтрымліваецца + Аўтарызацыя выканана + Жанры + Завершана + Ангоінг + Па змаўчанні + Не паказваць NSFW мангу з гісторыі + Паказваць нумары старонак + Уключаныя крыніцы + Даступныя крыніцы + Вылічэнні… + Дазваляць + Палітыка скрыншотаў + Заўсёды блакуйце + Блок на NSFW + Немагчыма загрузіць спіс жанраў + Непрацаздольны + Уключаны + Не прапануйце мангу NSFW + Пачніце чытаць мангу, і вы атрымаеце персаналізаваныя прапановы + Усе даныя аналізуюцца толькі лакальна на гэтай прыладзе і нікуды не адпраўляюцца. + Прапануеце мангу, заснаваную на вашых перавагах + Уключыць прапановы + Прапанова + Выберыце мову, на якой вы хочаце чытаць мангу. Вы зможаце змяніць гэта пазней. + Скінуць фільтр + Заўсёды + 18+ + Ніколі + Толькі праз Wi-Fi + Вы аўтарызаваны як %s + Папярэдняя загрузка старонак + Розныя мовы + Знайсці главу + %1$s%% + У гэтай манзе няма глаў + Схаваць + Знешні выгляд + Выключыць усё + Выкарыстоўваць адбітак пальца, калі даступна + Манга з абраных + Манга, якую вы нядаўна чыталі + Абнаўленне рэкамендацый + Апрацоўка захаванай мангі + Раздзелы будуць выдалены ў фонавым рэжыме + Правяраць новыя главы і паведамляць пра іх + Вы будзеце атрымліваць апавяшчэнні пра абнаўленні мангі, якую вы чытаеце + Вы не будзеце атрымліваць паведамленні, але новыя главы будуць паказаны ў спісе + Уключыць апавяшчэнні + Закладкі + Закладка выдалена + Закладка дадазена + Выдалена з гісторыі + DNS праз HTTPS + Аўтавызначэнне рэжыму чытання + Аўтаматычна вызначае, ці з’яўляецца манга вэбтунам + Даступныя новыя крыніцы мангі + Запавольванне спампоўкі + Выключыць жанры + Укажыце жанры, якія вы не хочаце бачыць у рэкамендацыях + Выдаліць выбраныя элементы з прылады назаўжды\? + Выдаленне завершана + Дапамагае пазбегнуць блакіроўкі па IP-адрасе + Выдаліць закладку + Рэжым па змаўчанні + Няма абраных катэгорый + Назва + Змяніць + Змяніць катэгорыю + Дадаць закладку + Адмяніць + Адключыць аптымізацыю акумулятара + Дапамагае з фонавай праверкай абнаўленняў + Штосьці пайшло не так. Калі ласка, адпраўце справаздачу пра памылку распрацоўшчыкам, каб дапамагчы нам яе выправіць. + Адправіць + Памылковы дамен + Справаздача + Адсочванне + Завершана + Адкладзена + Кінута + Паказваць індыкатары прагрэсу чытання + Запланавана + Чытаю + Выйсці + Паказваць працэнт прачытанага ў гісторыі і абраных + Выдаленне даных + Паказаць усе + Манга, пазначаная як NSFW, ніколі не будзе дададзеная ў гісторыю і ваш прагрэс не будзе захаваны + Можа дапамагчы з некаторымі праблемам. Усе аўтарызацыі будуць ануляваныя + Змесціва не знойдзена ці выдалена + Перачытваю + Выберыце дыяпазон + Тут нічога няма + Службы + Канадзе + Ачысціць усю гісторыю + Гісторыя ачышчана + Рэжым інкогніта + Вы ўпэўнены, што хочаце выдаліць выбраныя абраныя катэгорыі\? \nУся манга ў ім будзе страчана, і гэта нельга будзе адрабіць. - Вы можаце стварыць закладку падчас чытання мангі - Захаваная манга - Мамімі - Каб адсочваць ход чытання, выберыце Меню → Адсочваць на экране падрабязнасцей мангі. - Памылка сервера (%1$d). Калі ласка паспрабуйце зноў пазней - Таксама ачысціць інфармацыю аб новых раздзелах - Кампактны - Папярэдняя загрузка кантэнту - Пазначыць як бягучы - На прыладзе не засталося месца - Розныя мовы - Сетка недаступная - Каб чытаць мангу онлайн, уключыце Wi-Fi або мабільную сетку - Webtoon зум - Дынамічны - Каляровая гама - Мова - Уліковы запіс ужо існуе - Назад - Сінхранізацыя - Сінхранізацыя вашых дадзеных - Каб працягнуць, увядзіце свой адрас электроннай пошты - Вы можаце выдаліць зыходны файл са сховішча, каб зэканоміць месца - Хутка пачнецца імпарт - Дэталі памылкі:<br><tt>%1$s</tt><br><br>1. Паспрабуйце <a href=%2$s>адкрыць мангу ў вэб-браўзеры</a>, каб пераканацца, што яна даступная ў крыніцы<br>2. Упэўніцеся, што вы выкарыстоўваеце <a href=kotatsu://about>апошнюю версію Kotatsu</a><br>3. Калі ён даступны, адпраўце распрацоўнікам справаздачу аб памылцы. - Паказаць апошнія ярлыкі мангі - Зрабіце нядаўнюю мангу даступнай, доўга націскаючы на значок праграмы - Дакрананне да правага краю або націсканне правай клавішы заўсёды пераключае на наступную старонку - Эрганамічны упраўленне чытаннем - Карэкцыя колеру - Яркасць - Кантраст - Скінуць - Выбраныя налады колеру будуць запомнены для гэтай мангі - Захаваць ці адхіліць незахаваныя змены\? - Адмяніць - Уключыць запіс - Падзяліцца логамі - Запішыце некаторыя дзеянні для адладкі - Паказаць падазроны кантэнт - Ваша манга будзе адлюстроўвацца тут - Знайдзіце, што пачытаць, у раздзеле «Даследаваць» - Адменена - Кіраваць - Даступны - Стужка - Паказаць паўзунок пераключэння старонак - Крыніца адключана - Паказаць у выглядзе сеткі - Міку - Аска - Міён - Рыка - Сакура - Няма раздзелаў - Аўтаматычная пракрутка - Разд. %1$d/%2$d Стар. %3$d/%4$d - Паказаць інфармацыйную панэль у праграме чытання - Архіў коміксаў - Тэчка з малюнкамі - Імпарт мангі - Імпарт завершаны - Апошнія 2 гадзіны - Закладак пакуль няма - Закладкі выдалены - Няма крыніц мангі - Каб чытаць мангу онлайн, уключыце крыніцы мангі - Выпадковы - Змяніць парадак - Пуста - Дасьледуйце - Націсніце \"Назад\" яшчэ раз, каб выйсці - Двойчы націсніце \"Назад\", каб выйсці з праграмы - Пацверджанне выхаду - Кэш старонак - Іншы кэш - Выкарыстанне памяці - %s - %s - Выдалена з абраных - Параметры - Загаловак UserAgent - Дазволіць нестабільныя абнаўленні - Прапануйце абнаўленні да бэта-версій праграмы - Спампоўка пачалася - Калі ласка, перазапусціце праграму каб прымяніць змены - Зразумеў - Націсніце і ўтрымлівайце элемент, каб змяніць іх парадак - Вы можаце выбраць адзін або некалькі файлаў .cbz або .zip, кожны файл будзе распазнаны як асобная манга. - Вы можаце выбраць каталог з архівамі або выявамі. Кожны архіў (ці падкаталог) будзе прызнаны раздзелам. - Хуткасць - Імпарт раней створанай рэзервовай копіі дадзеных карыстальніка - Паказаць на паліцы - Знайсці падобныя - Вы можаце ўвайсці ў існуючы ўліковы запіс або стварыць новы - Налады сінхранізацыі - Адрас сервера - Выберыце люстэрка аўтаматычна - Аўтаматычна пераключаць дамены для аддаленых крыніц у выпадку памылак, калі даступныя люстэркі - Ігнараваць памылкі SSL - Аднавіць - Прыпынена - Адмяніць усё - Спампаваць толькі праз Wi-Fi - Вы можаце выкарыстоўваць уласны сервер сінхранізацыі або сервер па змаўчанні. Не змяняйце гэта, калі вы не ўпэўненыя, што робіце. - Паўза - Выдаліць завершаныя - Спыніць загрузку пры пераключэнні на мабільную сетку - Часам паказваць апавяшчэнні з прапанаванай мангай - Больш - Уключыць - Усе актыўныя спампоўкі будуць адменены, часткова спампаваныя даныя будуць страчаны - Хочаце атрымліваць персаналізаваныя прапановы мангі\? - Прапанова: %s - Не, дзякуй - Ваша гісторыя спамповак будзе выдалена назаўсёды - У вас няма загрузак - Спампоўкі аднавіліся - Спампоўкі прыпыненыя - Спампоўкі выдалены - Спампоўкі былі адменены - Пераклады - WebView недаступны: праверце, ці ўсталяваны пастаўшчык WebView - Тып - Адрас - Порт - Проксі - Ачысціць сеткавы кэш - %1$s (%2$s) - Няправільнае значэнне - \ No newline at end of file + Вы можаце стварыць закладку падчас чытання мангі + Захаваная манга + Мамімі + Каб адсочваць ход чытання, выберыце Меню → Адсочваць на экране падрабязнасцей мангі. + Памылка сервера (%1$d). Калі ласка паспрабуйце зноў пазней + Таксама ачысціць інфармацыю аб новых раздзелах + Кампактны + Папярэдняя загрузка кантэнту + Пазначыць як бягучы + На прыладзе не засталося месца + Розныя мовы + Сетка недаступная + Каб чытаць мангу онлайн, уключыце Wi-Fi або мабільную сетку + Webtoon зум + Дынамічны + Каляровая гама + Мова + Уліковы запіс ужо існуе + Назад + Сінхранізацыя + Сінхранізацыя вашых дадзеных + Каб працягнуць, увядзіце свой адрас электроннай пошты + Вы можаце выдаліць зыходны файл са сховішча, каб зэканоміць месца + Хутка пачнецца імпарт + Дэталі памылкі:<br><tt>%1$s</tt><br><br>1. Паспрабуйце <a href=%2$s>адкрыць мангу ў вэб-браўзеры</a>, каб пераканацца, што яна даступная ў крыніцы<br>2. Упэўніцеся, што вы выкарыстоўваеце <a href=kotatsu://about>апошнюю версію Kotatsu</a><br>3. Калі ён даступны, адпраўце распрацоўнікам справаздачу аб памылцы. + Паказаць апошнія ярлыкі мангі + Зрабіце нядаўнюю мангу даступнай, доўга націскаючы на значок праграмы + Дакрананне да правага краю або націсканне правай клавішы заўсёды пераключае на наступную старонку + Эрганамічны упраўленне чытаннем + Карэкцыя колеру + Яркасць + Кантраст + Скінуць + Выбраныя налады колеру будуць запомнены для гэтай мангі + Захаваць ці адхіліць незахаваныя змены\? + Адмяніць + Уключыць запіс + Падзяліцца логамі + Запішыце некаторыя дзеянні для адладкі + Паказаць падазроны кантэнт + Ваша манга будзе адлюстроўвацца тут + Знайдзіце, што пачытаць, у раздзеле «Даследаваць» + Адменена + Кіраваць + Даступны + Стужка + Паказаць паўзунок пераключэння старонак + Крыніца адключана + Паказаць у выглядзе сеткі + Міку + Аска + Міён + Рыка + Сакура + Няма раздзелаў + Аўтаматычная пракрутка + Разд. %1$d/%2$d Стар. %3$d/%4$d + Паказаць інфармацыйную панэль у праграме чытання + Архіў коміксаў + Тэчка з малюнкамі + Імпарт мангі + Імпарт завершаны + Апошнія 2 гадзіны + Закладак пакуль няма + Закладкі выдалены + Няма крыніц мангі + Каб чытаць мангу онлайн, уключыце крыніцы мангі + Выпадковы + Змяніць парадак + Пуста + Дасьледуйце + Націсніце \"Назад\" яшчэ раз, каб выйсці + Двойчы націсніце \"Назад\", каб выйсці з праграмы + Пацверджанне выхаду + Кэш старонак + Іншы кэш + Выкарыстанне памяці + %s - %s + Выдалена з абраных + Параметры + Загаловак UserAgent + Дазволіць нестабільныя абнаўленні + Прапануйце абнаўленні да бэта-версій праграмы + Спампоўка пачалася + Калі ласка, перазапусціце праграму каб прымяніць змены + Зразумеў + Націсніце і ўтрымлівайце элемент, каб змяніць іх парадак + Вы можаце выбраць адзін або некалькі файлаў .cbz або .zip, кожны файл будзе распазнаны як асобная манга. + Вы можаце выбраць каталог з архівамі або выявамі. Кожны архіў (ці падкаталог) будзе прызнаны раздзелам. + Хуткасць + Імпарт раней створанай рэзервовай копіі дадзеных карыстальніка + Паказаць на паліцы + Знайсці падобныя + Вы можаце ўвайсці ў існуючы ўліковы запіс або стварыць новы + Налады сінхранізацыі + Адрас сервера + Выберыце люстэрка аўтаматычна + Аўтаматычна пераключаць дамены для аддаленых крыніц у выпадку памылак, калі даступныя люстэркі + Ігнараваць памылкі SSL + Аднавіць + Прыпынена + Адмяніць усё + Спампаваць толькі праз Wi-Fi + Вы можаце выкарыстоўваць уласны сервер сінхранізацыі або сервер па змаўчанні. Не змяняйце гэта, калі вы не ўпэўненыя, што робіце. + Паўза + Выдаліць завершаныя + Спыніць загрузку пры пераключэнні на мабільную сетку + Часам паказваць апавяшчэнні з прапанаванай мангай + Больш + Уключыць + Усе актыўныя спампоўкі будуць адменены, часткова спампаваныя даныя будуць страчаны + Хочаце атрымліваць персаналізаваныя прапановы мангі\? + Прапанова: %s + Не, дзякуй + Ваша гісторыя спамповак будзе выдалена назаўсёды + У вас няма загрузак + Спампоўкі аднавіліся + Спампоўкі прыпыненыя + Спампоўкі выдалены + Спампоўкі былі адменены + Пераклады + WebView недаступны: праверце, ці ўсталяваны пастаўшчык WebView + Тып + Адрас + Порт + Проксі + Ачысціць сеткавы кэш + %1$s (%2$s) + Няправільнае значэнне + diff --git a/app/src/main/res/values-bn/plurals.xml b/app/src/main/res/values-bn/plurals.xml index d836ecb56..a90d74e48 100644 --- a/app/src/main/res/values-bn/plurals.xml +++ b/app/src/main/res/values-bn/plurals.xml @@ -1,15 +1,11 @@ - - %1$dটি আইটেম - %1$dটি আইটেম - - - সর্বমোট %1$dটি পেজ - সর্বমোট %1$dটি পেজ - - - %1$dটি নতুন চ্যাপ্টার - %1$dটি নতুন চ্যাপ্টার - - \ No newline at end of file + + %1$dটি আইটেম + %1$dটি আইটেম + + + %1$dটি নতুন চ্যাপ্টার + %1$dটি নতুন চ্যাপ্টার + + diff --git a/app/src/main/res/values-de/plurals.xml b/app/src/main/res/values-de/plurals.xml index c68adaa7b..57ba4ecdf 100644 --- a/app/src/main/res/values-de/plurals.xml +++ b/app/src/main/res/values-de/plurals.xml @@ -1,31 +1,27 @@ - - Insgesamt %1$d Seite - Insgesamt %1$d Seiten - - - %1$d Element - %1$d Elemente - - - %1$d neues Kapitel - %1$d neue Kapitel - - - %1$d Kapitel - %1$d Kapitel - - - Vor %1$d Minute - Vor %1$d Minuten - - - Vor %1$d Stunde - Vor %1$d Stunden - - - Vor %1$d Tag - Vor %1$d Tagen - - \ No newline at end of file + + %1$d Element + %1$d Elemente + + + %1$d neues Kapitel + %1$d neue Kapitel + + + %1$d Kapitel + %1$d Kapitel + + + Vor %1$d Minute + Vor %1$d Minuten + + + Vor %1$d Stunde + Vor %1$d Stunden + + + Vor %1$d Tag + Vor %1$d Tagen + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3198bc6bc..e7cb5fb89 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,415 +1,411 @@ - Entfernen - Gesamten Leseverlauf unwiderruflich löschen\? - Design - Seiten - Wie System - Dunkel - Hell - Filter - Sortierreihenfolge - Bewertung - Neuestes - Beliebt - Name - Downloads - Heruntergeladen - Manga suchen - Suchen - Teilen %s - Teilen - Speichern - Hinzufügen - Neue Kategorie - Zu Favoriten hinzufügen - Noch keine Favoriten - Lesen - Noch kein Verlauf - Nichts gefunden - Verlauf löschen - Erneut versuchen - Schließen - Kapitel %1$d von %2$d - Manga Quellen - Einstellungen - Listenmodus - Raster - Den gesamte Aktualisierungsverlauf unwiderruflich löschen\? - Keine Aktualisierungen verfügbar - Nach Aktualisierungen suchen - Suche nach Aktualisierungen - Die Feed-Aktualisierung beginnt gleich - Aktualisieren - Gelöscht - Aktualisierungsfeed löschen - Aktualisierungen - Eine neue Version der App ist verfügbar - Aktualisiert - Vorbereitung… - Hier ist es etwas leer… - Verarbeiten… - Herunterladen… - Verknüpfung erstellen… - Laden… - „%s“ unwiderruflich vom Gerät löschen\? - „%s“ aus lokalem Speicher gelöscht - Detaillierte Liste - Liste - Kapitel - Details - Netzwerkfehler - Ein Fehler ist aufgetreten - Verlauf - Favoriten - Lokaler Speicher - Ordner für Downloads - Die Manga, die du gerade liest, werden hier angezeigt - Am Anfang ausrichten - An Breite anpassen - An Höhe anpassen - Spart Energie auf AMOLED-Bildschirmen - Reines Schwarz - Von rechts nach links - Neue Kategorie - Backup und Wiederherstellung - Daten wiederhergestellt - Backup wiederherstellen - Backup erstellen - Datei nicht gefunden - Gerade jetzt - Gruppe - Alle Cookies wurden entfernt - Cookies löschen - Standard: %s - Melde dich an, um diesen Inhalt anzusehen - Umkehren - Nach neuen Kapiteln suchen - Feed löschen - Anmelden - Das Passwort muss mindestens 4 Zeichen lang sein - Bestätigen - Gib ein Passwort ein, mit dem die App gestartet werden soll - Weiter - Möchtest du alle letzten Suchanfragen unwiderruflich entfernen\? - Mehr erfahren - Einige Geräte haben ein anderes Systemverhalten, welches womöglich Hintergrundprozesse unterbricht. - Backup gespeichert - Willkommen - Entfernen - Bildschirm drehen - Größe: %s - Neue Version: %s - Suchergebnisse - Hier siehst du neue Kapitel der Mangas, die du liest - Später lesen - Diese Kategorie ist leer - Alle Favoriten - Fertig - Sonstiger Speicherort - Kein verfügbarer Speicher gefunden - Nicht verfügbar - Seitenanimation - Neueste Manga - Regal - Speicher Manga aus Online-Quellen oder importiere Dateien. - Speichere erst etwas - Was du lesen kannst, findest du im Seitenmenü. - Versuche, die Anfrage umzuformulieren. - Favoriten-Kategorien - Vibration - LED-Anzeige - Benachrichtigungston - Benachrichtigungseinstellungen - Herunterladen - Neue Kapitel - %1$d von %2$d aktiviert - Benachrichtigungen - Manga speichern - Dieser Manga hat %s. Alles davon speichern\? - Im Browser öffnen - Externer Speicher - Interner Speicher - Gelöscht - Suchverlauf löschen - Miniaturansichten Cache löschen - Fehler - Weiter - Lautstärketasten - Seiten wechseln - Leseeinstellungen - Manga löschen - Suche auf %s - Rastergröße - Lesemodus - Webtoon - Standard - B|kB|MB|GB|TB - Seitencache löschen - Verlauf und Cache - Keine Beschreibung - Wähle entweder eine ZIP- oder CBZ-Datei. - Dieser Vorgang wird nicht unterstützt - Löschen - Importieren - Bild teilen - Gespeichert - Seite speichern - Löschen - Rand antippen - Lösen - CAPTCHA erforderlich - Stumm - Die gewählte Konfiguration wird für diesen Manga gespeichert - Tippe, um es erneut zu versuchen - Heute - Vor langer Zeit - Gestern - Du kannst ein Backup deines Verlaufs und deiner Favoriten erstellen und wiederherstellen - Die Daten wurden wiederhergestellt, aber es gibt Fehler - Alle Daten wiederhergestellt - An Zentrum anpassen - Skalierungsmodus - Version %s - Über - Passwörter stimmen nicht überein - Wiederhole das Passwort - Beim Start von Kotatsu nach Passwort fragen - App schützen - Falsches Passwort - Passwort eingeben - Nicht prüfen - Domäne - Nur Gesten - Das Kapitel fehlt - Lade dieses fehlende Kapitel herunter oder lese es online. - In Warteschlange - Übersetzung - Übersetze die App - Du wirst von allen Quellen abgemeldet - Genres - Anmeldung bei %s wird nicht unterstützt - Autorisierung abgeschlossen - Beendet - Fortlaufend - Standard - NSFW-Manga vom Verlauf ausschließen - Nummerierte Seiten - Verwendete Quellen - Verfügbare Quellen - Berechnen… - Erlauben - Bildschirmfoto-Verhalten - Für NSFW blockieren - Immer blockieren - Vorschläge - Vorschläge einschalten - Schlage Manga basierend auf deinen Vorlieben vor - Alle Daten werden ausschließlich lokal auf diesem Gerät ausgewertet und nie weiter versendet. - Keine NSFW-Manga vorschlagen - Aktiviert - Beginne Manga zu lesen und du erhältst personalisierte Vorschläge - Deaktiviert - Liste der Genres kann nicht geladen werden - Nie - Immer - Seiten vorladen - Filter zurücksetzen - Genre finden - Nur über WLAN - Wähle die Sprachen aus, in denen du Mangas lesen möchten. Du kannst das später in den Einstellungen anpassen. - Angemeldet als %s - 18+ - Verschiedene Sprachen - Kapitel suchen - Keine Kapitel in diesem Manga - %1$s%% - Aussehen - Inhalt - Vorschläge werden aktualisiert - Genres ausschließen - Gebe Genres an, die du nicht in den Vorschlägen sehen möchtest - Ausgewählte Elemente unwiderruflich vom Gerät löschen\? - Entfernung abgeschlossen - Download-Verzögerung - Manga-Verarbeitung gespeichert - Hilft, das Blockieren deiner IP-Adresse zu vermeiden - Kapitel werden im Hintergrund entfernt - Ausblenden - Neue Manga-Quellen sind verfügbar - Nach neuen Kapiteln suchen und benachrichtigt werden - Erhalte Benachrichtigungen bei Aktualisierungen der Manga, die du liest - Benachrichtigungen einschalten - Keine bevorzugten Kategorien - Name - Bearbeiten - Du wirst keine Benachrichtigungen erhalten, aber neue Kapitel werden in den Listen hervorgehoben - Kategorie bearbeiten - Lesezeichen hinzufügen - Lesezeichen - Lesezeichen entfernt - Aus dem Verlauf entfernt - Lesezeichen entfernen - Lesezeichen hinzugefügt - Rückgängig - DNS über HTTPS - Standard-Modus - Automatische Erkennung des Modus - Automatisch erkennen, ob ein Manga ein Webtoon ist - Akkuoptimierung deaktivieren - Hilft bei der Hintergrundaktualisierung - Senden - Etwas ist schief gelaufen. Bitte sende einen Fehlerbericht an die Entwickler, um uns bei der Behebung zu helfen. - Alle deaktivieren - Fingerabdruck verwenden, falls verfügbar - Manga aus deinen Favoriten - Deine kürzlich gelesenen Manga - Melden - Nachverfolgung - Abmelden - Geplant - In der Warteschleife - Indikatoren für den Lesefortschritt anzeigen - Alle anzeigen - Zeige gelesenen Prozentsatz in Verlauf und Favoriten - Kann bei einigen Probleme helfen. Alle Anmeldungen werden ungültig - Abgeschlossen - Als NSFW markierte Manga werden nicht dem Verlauf beigefügt und dein Lesefortschritt wird nicht gespeichert - Datenlöschung - Ungültige Domain - Lese - Bereich auswählen - Inhalt nicht gefunden oder entfernt - Fehlerdetails:<br><tt>%1$s</tt><br><br>1. Versuche, <a href=%2$s>den Manga in einem Webbrowser zu öffnen</a>, um sicherzustellen, dass er bei seiner Quelle verfügbar ist<br>2. Stelle sicher, dass du die <a href=kotatsu://about>neueste Kotatsu-Version</a><br>3 benutzt. Wenn er verfügbar ist, sende einen Fehlerbericht an die Entwickler. - Noch keine Lesezeichen - Keine Manga-Quellen - Manga-Quellen aktivieren, um Manga online zu lesen - Beenden bestätigen - Gespeicherte Manga - Seiten-Cache - Anderer Cache - Speichernutzung - Verfügbar - %s - %s - Aus den Favoriten entfernt - Optionen - Automatisches Blättern - Comics-Archiv - Kap. %1$d/%2$d S. %3$d/%4$d - Deine Manga werden hier angezeigt - Finde etwas zu lesen in der Rubrik „Erkunden“ - Abgebrochen - Konto existiert bereits - Zurück - Synchronisierung - Synchronisiere deine Daten - Gib deine E-Mail-Adresse ein, um fortzufahren - Gesamten Verlauf löschen - Letzte 2 Stunden - Verlauf gelöscht - Verwalten - Du kannst beim Lesen von Mangas Lesezeichen erstellen - Lesezeichen entfernt - Zufällig - Bist du sicher, dass du die ausgewählten Lieblingskategorien löschen möchtest\? + Entfernen + Gesamten Leseverlauf unwiderruflich löschen\? + Design + Seiten + Wie System + Dunkel + Hell + Filter + Sortierreihenfolge + Bewertung + Neuestes + Beliebt + Name + Downloads + Heruntergeladen + Manga suchen + Suchen + Teilen %s + Teilen + Speichern + Hinzufügen + Neue Kategorie + Zu Favoriten hinzufügen + Noch keine Favoriten + Lesen + Noch kein Verlauf + Nichts gefunden + Verlauf löschen + Erneut versuchen + Schließen + Kapitel %1$d von %2$d + Manga Quellen + Einstellungen + Listenmodus + Raster + Den gesamte Aktualisierungsverlauf unwiderruflich löschen\? + Keine Aktualisierungen verfügbar + Nach Aktualisierungen suchen + Suche nach Aktualisierungen + Die Feed-Aktualisierung beginnt gleich + Aktualisieren + Gelöscht + Aktualisierungsfeed löschen + Aktualisierungen + Eine neue Version der App ist verfügbar + Aktualisiert + Vorbereitung… + Hier ist es etwas leer… + Verarbeiten… + Herunterladen… + Verknüpfung erstellen… + Laden… + „%s“ unwiderruflich vom Gerät löschen\? + „%s“ aus lokalem Speicher gelöscht + Detaillierte Liste + Liste + Kapitel + Details + Netzwerkfehler + Ein Fehler ist aufgetreten + Verlauf + Favoriten + Lokaler Speicher + Ordner für Downloads + Die Manga, die du gerade liest, werden hier angezeigt + Am Anfang ausrichten + An Breite anpassen + An Höhe anpassen + Spart Energie auf AMOLED-Bildschirmen + Reines Schwarz + Von rechts nach links + Neue Kategorie + Backup und Wiederherstellung + Daten wiederhergestellt + Backup wiederherstellen + Backup erstellen + Datei nicht gefunden + Gerade jetzt + Gruppe + Alle Cookies wurden entfernt + Cookies löschen + Standard: %s + Melde dich an, um diesen Inhalt anzusehen + Umkehren + Nach neuen Kapiteln suchen + Feed löschen + Anmelden + Das Passwort muss mindestens 4 Zeichen lang sein + Bestätigen + Gib ein Passwort ein, mit dem die App gestartet werden soll + Weiter + Möchtest du alle letzten Suchanfragen unwiderruflich entfernen\? + Mehr erfahren + Einige Geräte haben ein anderes Systemverhalten, welches womöglich Hintergrundprozesse unterbricht. + Backup gespeichert + Willkommen + Entfernen + Bildschirm drehen + Größe: %s + Neue Version: %s + Suchergebnisse + Hier siehst du neue Kapitel der Mangas, die du liest + Später lesen + Diese Kategorie ist leer + Alle Favoriten + Fertig + Sonstiger Speicherort + Kein verfügbarer Speicher gefunden + Nicht verfügbar + Seitenanimation + Neueste Manga + Regal + Speicher Manga aus Online-Quellen oder importiere Dateien. + Speichere erst etwas + Was du lesen kannst, findest du im Seitenmenü. + Versuche, die Anfrage umzuformulieren. + Favoriten-Kategorien + Vibration + LED-Anzeige + Benachrichtigungston + Benachrichtigungseinstellungen + Herunterladen + Neue Kapitel + %1$d von %2$d aktiviert + Benachrichtigungen + Manga speichern + Dieser Manga hat %s. Alles davon speichern\? + Im Browser öffnen + Externer Speicher + Interner Speicher + Gelöscht + Suchverlauf löschen + Miniaturansichten Cache löschen + Fehler + Weiter + Lautstärketasten + Seiten wechseln + Leseeinstellungen + Manga löschen + Suche auf %s + Rastergröße + Lesemodus + Webtoon + Standard + B|kB|MB|GB|TB + Seitencache löschen + Keine Beschreibung + Wähle entweder eine ZIP- oder CBZ-Datei. + Dieser Vorgang wird nicht unterstützt + Löschen + Importieren + Bild teilen + Gespeichert + Seite speichern + Löschen + Rand antippen + Lösen + CAPTCHA erforderlich + Stumm + Die gewählte Konfiguration wird für diesen Manga gespeichert + Tippe, um es erneut zu versuchen + Heute + Vor langer Zeit + Gestern + Du kannst ein Backup deines Verlaufs und deiner Favoriten erstellen und wiederherstellen + Die Daten wurden wiederhergestellt, aber es gibt Fehler + Alle Daten wiederhergestellt + An Zentrum anpassen + Skalierungsmodus + Version %s + Über + Passwörter stimmen nicht überein + Wiederhole das Passwort + Beim Start von Kotatsu nach Passwort fragen + App schützen + Falsches Passwort + Passwort eingeben + Nicht prüfen + Domäne + Nur Gesten + Das Kapitel fehlt + In Warteschlange + Übersetzung + Übersetze die App + Du wirst von allen Quellen abgemeldet + Genres + Anmeldung bei %s wird nicht unterstützt + Autorisierung abgeschlossen + Beendet + Fortlaufend + Standard + NSFW-Manga vom Verlauf ausschließen + Nummerierte Seiten + Verwendete Quellen + Verfügbare Quellen + Berechnen… + Erlauben + Bildschirmfoto-Verhalten + Für NSFW blockieren + Immer blockieren + Vorschläge + Vorschläge einschalten + Schlage Manga basierend auf deinen Vorlieben vor + Alle Daten werden ausschließlich lokal auf diesem Gerät ausgewertet und nie weiter versendet. + Keine NSFW-Manga vorschlagen + Aktiviert + Beginne Manga zu lesen und du erhältst personalisierte Vorschläge + Deaktiviert + Liste der Genres kann nicht geladen werden + Nie + Immer + Seiten vorladen + Filter zurücksetzen + Nur über WLAN + Wähle die Sprachen aus, in denen du Mangas lesen möchten. Du kannst das später in den Einstellungen anpassen. + Angemeldet als %s + 18+ + Verschiedene Sprachen + Kapitel suchen + Keine Kapitel in diesem Manga + %1$s%% + Aussehen + Vorschläge werden aktualisiert + Genres ausschließen + Gebe Genres an, die du nicht in den Vorschlägen sehen möchtest + Ausgewählte Elemente unwiderruflich vom Gerät löschen\? + Entfernung abgeschlossen + Download-Verzögerung + Manga-Verarbeitung gespeichert + Hilft, das Blockieren deiner IP-Adresse zu vermeiden + Kapitel werden im Hintergrund entfernt + Ausblenden + Neue Manga-Quellen sind verfügbar + Nach neuen Kapiteln suchen und benachrichtigt werden + Erhalte Benachrichtigungen bei Aktualisierungen der Manga, die du liest + Benachrichtigungen einschalten + Keine bevorzugten Kategorien + Name + Bearbeiten + Du wirst keine Benachrichtigungen erhalten, aber neue Kapitel werden in den Listen hervorgehoben + Kategorie bearbeiten + Lesezeichen hinzufügen + Lesezeichen + Lesezeichen entfernt + Aus dem Verlauf entfernt + Lesezeichen entfernen + Lesezeichen hinzugefügt + Rückgängig + DNS über HTTPS + Standard-Modus + Automatische Erkennung des Modus + Automatisch erkennen, ob ein Manga ein Webtoon ist + Akkuoptimierung deaktivieren + Hilft bei der Hintergrundaktualisierung + Senden + Etwas ist schief gelaufen. Bitte sende einen Fehlerbericht an die Entwickler, um uns bei der Behebung zu helfen. + Alle deaktivieren + Fingerabdruck verwenden, falls verfügbar + Manga aus deinen Favoriten + Deine kürzlich gelesenen Manga + Melden + Nachverfolgung + Abmelden + Geplant + In der Warteschleife + Indikatoren für den Lesefortschritt anzeigen + Alle anzeigen + Zeige gelesenen Prozentsatz in Verlauf und Favoriten + Kann bei einigen Probleme helfen. Alle Anmeldungen werden ungültig + Abgeschlossen + Als NSFW markierte Manga werden nicht dem Verlauf beigefügt und dein Lesefortschritt wird nicht gespeichert + Datenlöschung + Ungültige Domain + Lese + Bereich auswählen + Inhalt nicht gefunden oder entfernt + Fehlerdetails:<br><tt>%1$s</tt><br><br>1. Versuche, <a href=%2$s>den Manga in einem Webbrowser zu öffnen</a>, um sicherzustellen, dass er bei seiner Quelle verfügbar ist<br>2. Stelle sicher, dass du die <a href=kotatsu://about>neueste Kotatsu-Version</a><br>3 benutzt. Wenn er verfügbar ist, sende einen Fehlerbericht an die Entwickler. + Noch keine Lesezeichen + Keine Manga-Quellen + Manga-Quellen aktivieren, um Manga online zu lesen + Beenden bestätigen + Gespeicherte Manga + Seiten-Cache + Anderer Cache + Speichernutzung + Verfügbar + %s - %s + Aus den Favoriten entfernt + Optionen + Automatisches Blättern + Comics-Archiv + Kap. %1$d/%2$d S. %3$d/%4$d + Deine Manga werden hier angezeigt + Finde etwas zu lesen in der Rubrik „Erkunden“ + Abgebrochen + Konto existiert bereits + Zurück + Synchronisierung + Synchronisiere deine Daten + Gib deine E-Mail-Adresse ein, um fortzufahren + Gesamten Verlauf löschen + Letzte 2 Stunden + Verlauf gelöscht + Verwalten + Du kannst beim Lesen von Mangas Lesezeichen erstellen + Lesezeichen entfernt + Zufällig + Bist du sicher, dass du die ausgewählten Lieblingskategorien löschen möchtest\? \nAlle darin enthaltenen Manga gehen verloren und das kann nicht rückgängig gemacht werden. - Neu anordnen - Leer - Erkunden - Drücke zum Beenden erneut Zurück - Drücke zweimal Zurück, um die App zu beenden - Feed - Inkognito-Modus - Keine Kapitel - Zeige Informationsleiste beim Lesen - Ordner mit Bildern - Importiere Manga - Import abgeschlossen - Du kannst die Originaldatei aus dem Speicher löschen, um Platz zu sparen - Import wird bald beginnen - Serverseitiger Fehler (%1$d). Bitte versuche es später erneut - Kompakt - Kontrast - Schalte WLAN oder mobile Daten ein, um Manga online zu lesen - Auch Informationen über neue Kapitel löschen - Ungespeicherte Änderungen speichern oder verwerfen\? - Verwerfen - Zurücksetzen - Helligkeit - Die gewählten Farbeinstellungen werden für diesen Manga beibehalten - Farbkorrektur - Kein Platz übrig auf dem Gerät - Verschiedene Sprachen - Netzwerk ist nicht verfügbar - Ergonomische Lesekontrolle - Tippe auf den rechten Rand oder drücke die rechte Taste, um immer zur nächsten Seite zu wechseln - Zeige Seitenwechsel-Schieber - Quelle deaktiviert - Inhalte vorladen - Als aktuell markieren - Webtoon-Zoom - Protokolle teilen - Protokollierung aktivieren - Sprache - Einige Aktionen zu Debug-Zwecken aufzeichnen - Zeige Verknüpfungen zu aktuellen Manga - Neueste Manga durch langes Drücken auf das Anwendungssymbol verfügbar machen - Verdächtige Inhalte anzeigen - Abgebrochen - Farbschema - Dynamisch - Mamimi - Hier ist nichts - Dienste - Kanade - Um deinen Lesefortschritt nachzuverfolgen, wähle Menu → Track auf dem Manga Details Bildschirm. - Ähnliche finden - Sakura - Schlage Updates zu Beta-Versionen der App vor - Erlaube instabile Updates - Alles klar - Drücke und halte eine Quelle, um diese umzusortieren - Bitte starte die App neu, um die Änderungen anzuwenden - Du kannst eine oder mehrere .cbz oder .zip Dateien auswählen, jede Datei wird als einzelner Manga erkannt. - Du kannst einen Ordner mit Archiven oder Bildern auswählen. Jedes Archiv (oder Unterverzeichnis) wird als ein Kapitel erkannt. - Geschwindigkeit - Importiere ein zuvor erstelltes Nutzerdaten-Backup - Im Regal anzeigen - Miku - Asuka - Mion - Rikka - In Raster-Ansicht anzeigen - Serveradresse - Wähle Mirror automatisch - Download gestartet - Synchronisationseinstellungen - Du kannst einen Standard- oder einen selbst gehosteten Synchronisations-Server verwenden. Ändere diese Einstellungen nicht, wenn du dich nicht auskennst. - Ignoriere SSL Errors - Wechsel bei Fehlern automatisch die Domains für Manga-Quellen, falls Mirrors verfügbar sind - Lese erneut - Du kannst dich mit einem bestehenden Account anmelden oder einen neuen erstellen - UserAgent-Kopfzeile - Aktivieren - Nein danke - Pausieren - Fortsetzen - Pausiert - Entfernung abgeschlossen - Alle abbrechen - Nur über Wi-Fi herunterladen - Beende das Herunterladen beim Wechsel zu einem Mobilfunknetz - Zeige ab und zu Benachrichtigungen mit Manga-Vorschlägen - Downloads wurden entfernt - Vorschlag: %s - Mehr - Alle Downloads werden abgebrochen, teilweise heruntergeladene Dateien gehen verloren - Dein Downloads-Verlauf wird unwiderruflich gelöscht - Du hast keine Downloads - Downloads wurden fortgesetzt - Downloads wurden pausiert - Downloads wurden abgebrochen - Willst du personalisierte Manga-Vorschläge erhalten\? - Übersetzungen - WebView nicht verfügbar: überprüfe, ob WebView installiert ist - \ No newline at end of file + Neu anordnen + Leer + Erkunden + Drücke zum Beenden erneut Zurück + Drücke zweimal Zurück, um die App zu beenden + Feed + Inkognito-Modus + Keine Kapitel + Zeige Informationsleiste beim Lesen + Ordner mit Bildern + Importiere Manga + Import abgeschlossen + Du kannst die Originaldatei aus dem Speicher löschen, um Platz zu sparen + Import wird bald beginnen + Serverseitiger Fehler (%1$d). Bitte versuche es später erneut + Kompakt + Kontrast + Schalte WLAN oder mobile Daten ein, um Manga online zu lesen + Auch Informationen über neue Kapitel löschen + Ungespeicherte Änderungen speichern oder verwerfen\? + Verwerfen + Zurücksetzen + Helligkeit + Die gewählten Farbeinstellungen werden für diesen Manga beibehalten + Farbkorrektur + Kein Platz übrig auf dem Gerät + Verschiedene Sprachen + Netzwerk ist nicht verfügbar + Ergonomische Lesekontrolle + Tippe auf den rechten Rand oder drücke die rechte Taste, um immer zur nächsten Seite zu wechseln + Zeige Seitenwechsel-Schieber + Quelle deaktiviert + Inhalte vorladen + Als aktuell markieren + Webtoon-Zoom + Protokolle teilen + Protokollierung aktivieren + Sprache + Einige Aktionen zu Debug-Zwecken aufzeichnen + Zeige Verknüpfungen zu aktuellen Manga + Neueste Manga durch langes Drücken auf das Anwendungssymbol verfügbar machen + Verdächtige Inhalte anzeigen + Abgebrochen + Farbschema + Dynamisch + Mamimi + Hier ist nichts + Dienste + Kanade + Um deinen Lesefortschritt nachzuverfolgen, wähle Menu → Track auf dem Manga Details Bildschirm. + Ähnliche finden + Sakura + Schlage Updates zu Beta-Versionen der App vor + Erlaube instabile Updates + Alles klar + Drücke und halte eine Quelle, um diese umzusortieren + Bitte starte die App neu, um die Änderungen anzuwenden + Du kannst eine oder mehrere .cbz oder .zip Dateien auswählen, jede Datei wird als einzelner Manga erkannt. + Du kannst einen Ordner mit Archiven oder Bildern auswählen. Jedes Archiv (oder Unterverzeichnis) wird als ein Kapitel erkannt. + Geschwindigkeit + Importiere ein zuvor erstelltes Nutzerdaten-Backup + Im Regal anzeigen + Miku + Asuka + Mion + Rikka + In Raster-Ansicht anzeigen + Serveradresse + Wähle Mirror automatisch + Download gestartet + Synchronisationseinstellungen + Du kannst einen Standard- oder einen selbst gehosteten Synchronisations-Server verwenden. Ändere diese Einstellungen nicht, wenn du dich nicht auskennst. + Ignoriere SSL Errors + Wechsel bei Fehlern automatisch die Domains für Manga-Quellen, falls Mirrors verfügbar sind + Lese erneut + Du kannst dich mit einem bestehenden Account anmelden oder einen neuen erstellen + UserAgent-Kopfzeile + Aktivieren + Nein danke + Pausieren + Fortsetzen + Pausiert + Entfernung abgeschlossen + Alle abbrechen + Nur über Wi-Fi herunterladen + Beende das Herunterladen beim Wechsel zu einem Mobilfunknetz + Zeige ab und zu Benachrichtigungen mit Manga-Vorschlägen + Downloads wurden entfernt + Vorschlag: %s + Mehr + Alle Downloads werden abgebrochen, teilweise heruntergeladene Dateien gehen verloren + Dein Downloads-Verlauf wird unwiderruflich gelöscht + Du hast keine Downloads + Downloads wurden fortgesetzt + Downloads wurden pausiert + Downloads wurden abgebrochen + Willst du personalisierte Manga-Vorschläge erhalten\? + Übersetzungen + WebView nicht verfügbar: überprüfe, ob WebView installiert ist + diff --git a/app/src/main/res/values-el/plurals.xml b/app/src/main/res/values-el/plurals.xml index 08b7f5084..edbd58db0 100644 --- a/app/src/main/res/values-el/plurals.xml +++ b/app/src/main/res/values-el/plurals.xml @@ -20,10 +20,6 @@ %1$dκεφάλαιο %1$dκεφάλαια - - Σύνολο%1$dσελίδα - Σύνολο%1$dσελίδες - %1$dλεπτό πριν %1$d λεπτά πριν diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index d7bf6d6b4..0186123b3 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -42,7 +42,6 @@ Διαγραφή Επιλέξτε ένα αρχείο ZIP ή CBZ. Χωρίς περιγραφή - Ιστορικό και μνήμη cache Εκκαθάριση μνήμης cache της σελίδας B|kB|MB|GB|TB Τυπικό diff --git a/app/src/main/res/values-es/plurals.xml b/app/src/main/res/values-es/plurals.xml index f5f4a4cbb..10d2afcd6 100644 --- a/app/src/main/res/values-es/plurals.xml +++ b/app/src/main/res/values-es/plurals.xml @@ -1,38 +1,33 @@ - - Página total %1$d - Páginas totales %1$d - Página totales %1$d - - - %1$d elemento - %1$d elementos - %1$d elementos - - - %1$d nuevo capítulo - %1$d nuevos capítulos - %1$d nuevos capítulos - - - %1$d capítulo - %1$d capítulos - %1$d capítulos - - - hace %1$d minuto - hace %1$d minutos - hace %1$d minutos - - - hace %1$d hora - hace %1$d horas - hace %1$d horas - - - hace %1$d día - hace %1$d días - hace %1$d días - - \ No newline at end of file + + %1$d elemento + %1$d elementos + %1$d elementos + + + %1$d nuevo capítulo + %1$d nuevos capítulos + %1$d nuevos capítulos + + + %1$d capítulo + %1$d capítulos + %1$d capítulos + + + hace %1$d minuto + hace %1$d minutos + hace %1$d minutos + + + hace %1$d hora + hace %1$d horas + hace %1$d horas + + + hace %1$d día + hace %1$d días + hace %1$d días + + diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index ae1169138..09dec10e3 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,429 +1,425 @@ - Dispositivo - Favoritos - Historial - Ocurrió un error - Error en la red - Detalles - Capítulos - Lista - Lista detallada - Cuadrículas - Vista de lista - Ajustes - Fuentes del manga - Cargando… - Capítulo %1$d de %2$d - Cerrar - Reintentar - Borrar historial - No se encontró nada - Aún sin historial - Leer - Aún no hay favoritos - Añadir a favoritos - Nueva categoría - Añadir - Guardar - Compartir - Crear acceso directo… - Compartir %s - Buscar - Buscar manga - Descargando… - Procesando… - Descargado - Descargas - Nombre - Popularidad - Actualización - Recientes - Calificación - Orden de clasificación - Filtrar - Tema - Claro - Oscuro - De acuerdo al sistema - Páginas - Borrar - Borrar todo el historial de lectura de forma permanente\? - Eliminar - «%s» borrado del almacenamiento local - Guardar página - Guardado - Compartir imagen - Importar - Borrar - Esta operación no está admitida - Elija un archivo ZIP o bien un archivo CBZ. - Sin descripción - Historial y caché - Borrar caché de página - B|kB|MB|GB|TB - Estándar - Sitio web - Modo de lectura - Tamaño de la cuadrícula - Buscar en %s - Borrar manga - ¿Borrar \"%s\" del dispositivo permanentemente\? - Ajustes del lector - Cambiar de página - Toques de borde - Botones de volumen - Continuar - Error - Borrar la caché de miniaturas - Borrar el historial de búsqueda - Historial de búsqueda borrado - Sólo gestos - Almacenamiento interno - Almacenamiento externo - Dominio - Una nueva versión de la aplicación está disponible - Abrir en navegador web - Este manga tiene %s. ¿Quieres guardarlo todo\? - Guardar - Notificaciones - Activado %1$d de %2$d - Nuevos capítulos - Descargar - Configuración de las notificaciones - Sonido de las notificaciones - Indicador LED - Vibración - Categorías favoritas - Remover - Estante - Reciente - Animación de página - Carpeta para descargas - No disponible - No hay almacenamiento disponible - Otro almacenamiento - Aceptar - Todos los favoritos - Categoría vacía - Leer más tarde - Actualizaciones - Aquí verás los nuevos episodios del manga que estás leyendo - Resultados de la búsqueda - Nueva versión: %s - Tamaño: %s - Borrar actualizaciones - Borrar el feed de actualizaciones - Girar pantalla - Actualizar - La actualización de la alimentación comenzará pronto - Comprueba las actualizaciones del manga - No comprobar - Introducir contraseña - Contraseña incorrecta - Proteger aplicación - Pedir una contraseña al iniciar Kotatsu - Repite la contraseña - Las contraseñas no coinciden - Acerca de - Versión %s - Comprobar actualizaciones - No hay actualizaciones disponibles - De derecha a izquierda - Nueva categoría - Modo de escala - Ajuste al centro - Ajuste a la altura - Ajuste a la anchura - Mantener al iniciar - Tema oscuro auténtico - Útil para pantallas AMOLED - Respaldo y restauración - Crear copia de seguridad de datos - Restaurar desde la copia de seguridad - Datos restaurados - Preparando… - Archivo no encontrado - Todos los datos fueron restaurados con éxito - Los datos fueron restaurados, pero hay errores - Puedes crear una copia de seguridad de tu historial y favoritos para restaurarla - Ahora mismo - Ayer - Hace mucho tiempo - Grupo - Hoy - Toca para volver a intentar - Se recordará la configuración elegida para este manga - Silenciar - El captcha es obligatorio - Resolver - Borrar cookies - Se han eliminado todas las cookies - Limpiar feed - Todo el historial de actualizaciones se borrará y esta acción no se puede deshacer. ¿Está seguro\? - Comprobación de nuevos capítulos - Invertir - Iniciar sesión - Debes autorizar para ver este contenido - Por defecto: %s - Siguiente - Introduce la contraseña que se requerirá cuando se inicie la aplicación - Confirmar - La contraseña debe tener al menos 4 caracteres - Puedes guardarlo desde fuentes in línea o importarlo desde un archivo. - Todavía no tienes ningún manga guardado - Encuentra qué leer en el menú lateral. - Lo que leas se mostrará aquí - Está un poco vacío aquí… - Falta un capítulo - Traducir esta aplicación - Traducción - En la cola - Leer más - Copia de seguridad guardada correctamente - Bienvenido/a - Géneros - Intenta reformular la consulta. - ¿Realmente quiere eliminar todas las consultas de búsqueda recientes\? - Terminado - En curso - Este capítulo no aparece en su dispositivo. Descárguelo o léalo en línea. - Autorizado - Por defecto - Algunos fabricantes pueden cambiar el comportamiento del sistema, lo que podría interrumpir las tareas en segundo plano. - No se admite iniciar sesión en %s - Serás desconectado de todas las fuentes - Excluye manga NSFW del historial - Mostrar los números de páginas - Fuentes activadas - Fuentes disponibles - Informática… - Política de capturas de pantalla - Permitir - Bloquear siempre - Sugerencias - Activar sugerencias - Sugiere mangas según tus preferencias - Todos los datos sólo se analizan localmente en este dispositivo y nunca se envían a ninguna parte. - Empieza a leer manga y recibirás sugerencias personalizadas - No sugerir manga NSFW - Activado - Desactivado - No se puede cargar la lista de géneros - Bloqueo en NSFW - Conectado como %s - Encontrar el género - Selecciona los idiomas en los que quieres leer mangas. Puedes cambiarlo más tarde en los ajustes. - Reiniciar el filtro - Nunca - 18+ - Siempre - Precargar las páginas - Sólo en Wi-Fi - Varios idiomas - Buscar capítulo - No hay capítulos en este manga - %1$s%% - Aspecto - Contenido - Actualización de las sugerencias - Excluir géneros - Especifica los géneros que no quieres ver en las sugerencias - Remoción completada - ¿Eliminar elementos seleccionados del dispositivo de forma permanente\? - Ocultar - Ralentización de la descarga - Nuevas fuentes de manga son disponibles - Ayuda a evitar el bloqueo de tu dirección IP - Procesamiento de manga guardado - Comprueba si hay nuevos capítulos y notifica sobre ellos - Recibirás notificaciones sobre las actualizaciones del manga que estés leyendo - Añadir marcador - Marcadores - Deshacer - Marcador eliminado - Eliminado del historial - Eliminar marcador - Añadido a favoritos - DNS mediante HTTPS - Modo predeterminado - Autodetectar modo de lectura - Detecta automáticamente si el manga es un webtoon - Los capítulos se eliminarán en segundo plano - No recibirás notificaciones, pero los nuevos capítulos aparecerán destacados en las listas - Activar las notificaciones - No hay categorías favoritas - Nombre - Editar - Editar categoría - Desactivar todo - Desactivar la optimización de la batería - Enviar - Algo ha ido mal. Por favor, envía un informe de errores a los desarrolladores para ayudarnos a solucionarlo. - Utilizar la huella dactilar si está disponible - Mangas de tus favoritos - Sus mangas recientemente leídos - Cerrar sesión - Planeado - Lectura - Abandonado - En espera - Informar - Seguimiento - Ayuda con las comprobaciones de las actualizaciones en segundo plano - Relectura - Completado - Mostrar indicadores de progreso en la lectura - Eliminación de datos - Mostrar porcentaje de lectura en el historial y en los favoritos - El manga marcado como NSFW nunca se añadirá al historial y no se guardará tu progreso - Puede ayudar en caso de algunos problemas. Todas las autorizaciones serán invalidadas - Mostrar todo - Dominio no válido - Encuentra qué leer en la sección «Explorar» - La cuenta ya existe - Sincronización - Introduce tu correo electrónico para continuar - Últimas 2 horas - Todavía no hay marcadores - Puedes crear marcadores mientras lees el manga - Marcadores eliminados - Habilitar las fuentes de manga para leer manga en línea - Aleatorio - Reordenar - Vacío - Otro caché - Uso del almacenamiento - Disponible - Eliminado de los favoritos - Opciones - Modo incógnito - No hay capítulos - Mostrar la barra de información en el lector - Importando el manga - Importación completada - La importación comenzará pronto - Cancelado - Atrás - Sincronizar tus datos - Tu manga se mostrará aquí - Borrar todo el historial - Sin fuentes de manga - Historial borrado - Gestionar - Pulsa de nuevo «Atrás» para salir - Carpeta con imágenes - ¿Estás seguro de que quieres eliminar las categorías favoritas seleccionadas\? + Dispositivo + Favoritos + Historial + Ocurrió un error + Error en la red + Detalles + Capítulos + Lista + Lista detallada + Cuadrículas + Vista de lista + Ajustes + Fuentes del manga + Cargando… + Capítulo %1$d de %2$d + Cerrar + Reintentar + Borrar historial + No se encontró nada + Aún sin historial + Leer + Aún no hay favoritos + Añadir a favoritos + Nueva categoría + Añadir + Guardar + Compartir + Crear acceso directo… + Compartir %s + Buscar + Buscar manga + Descargando… + Procesando… + Descargado + Descargas + Nombre + Popularidad + Actualización + Recientes + Calificación + Orden de clasificación + Filtrar + Tema + Claro + Oscuro + De acuerdo al sistema + Páginas + Borrar + Borrar todo el historial de lectura de forma permanente\? + Eliminar + «%s» borrado del almacenamiento local + Guardar página + Guardado + Compartir imagen + Importar + Borrar + Esta operación no está admitida + Elija un archivo ZIP o bien un archivo CBZ. + Sin descripción + Borrar caché de página + B|kB|MB|GB|TB + Estándar + Sitio web + Modo de lectura + Tamaño de la cuadrícula + Buscar en %s + Borrar manga + ¿Borrar \"%s\" del dispositivo permanentemente\? + Ajustes del lector + Cambiar de página + Toques de borde + Botones de volumen + Continuar + Error + Borrar la caché de miniaturas + Borrar el historial de búsqueda + Historial de búsqueda borrado + Sólo gestos + Almacenamiento interno + Almacenamiento externo + Dominio + Una nueva versión de la aplicación está disponible + Abrir en navegador web + Este manga tiene %s. ¿Quieres guardarlo todo\? + Guardar + Notificaciones + Activado %1$d de %2$d + Nuevos capítulos + Descargar + Configuración de las notificaciones + Sonido de las notificaciones + Indicador LED + Vibración + Categorías favoritas + Remover + Estante + Reciente + Animación de página + Carpeta para descargas + No disponible + No hay almacenamiento disponible + Otro almacenamiento + Aceptar + Todos los favoritos + Categoría vacía + Leer más tarde + Actualizaciones + Aquí verás los nuevos episodios del manga que estás leyendo + Resultados de la búsqueda + Nueva versión: %s + Tamaño: %s + Borrar actualizaciones + Borrar el feed de actualizaciones + Girar pantalla + Actualizar + La actualización de la alimentación comenzará pronto + Comprueba las actualizaciones del manga + No comprobar + Introducir contraseña + Contraseña incorrecta + Proteger aplicación + Pedir una contraseña al iniciar Kotatsu + Repite la contraseña + Las contraseñas no coinciden + Acerca de + Versión %s + Comprobar actualizaciones + No hay actualizaciones disponibles + De derecha a izquierda + Nueva categoría + Modo de escala + Ajuste al centro + Ajuste a la altura + Ajuste a la anchura + Mantener al iniciar + Tema oscuro auténtico + Útil para pantallas AMOLED + Respaldo y restauración + Crear copia de seguridad de datos + Restaurar desde la copia de seguridad + Datos restaurados + Preparando… + Archivo no encontrado + Todos los datos fueron restaurados con éxito + Los datos fueron restaurados, pero hay errores + Puedes crear una copia de seguridad de tu historial y favoritos para restaurarla + Ahora mismo + Ayer + Hace mucho tiempo + Grupo + Hoy + Toca para volver a intentar + Se recordará la configuración elegida para este manga + Silenciar + El captcha es obligatorio + Resolver + Borrar cookies + Se han eliminado todas las cookies + Limpiar feed + Todo el historial de actualizaciones se borrará y esta acción no se puede deshacer. ¿Está seguro\? + Comprobación de nuevos capítulos + Invertir + Iniciar sesión + Debes autorizar para ver este contenido + Por defecto: %s + Siguiente + Introduce la contraseña que se requerirá cuando se inicie la aplicación + Confirmar + La contraseña debe tener al menos 4 caracteres + Puedes guardarlo desde fuentes in línea o importarlo desde un archivo. + Todavía no tienes ningún manga guardado + Encuentra qué leer en el menú lateral. + Lo que leas se mostrará aquí + Está un poco vacío aquí… + Falta un capítulo + Traducir esta aplicación + Traducción + En la cola + Leer más + Copia de seguridad guardada correctamente + Bienvenido/a + Géneros + Intenta reformular la consulta. + ¿Realmente quiere eliminar todas las consultas de búsqueda recientes\? + Terminado + En curso + Autorizado + Por defecto + Algunos fabricantes pueden cambiar el comportamiento del sistema, lo que podría interrumpir las tareas en segundo plano. + No se admite iniciar sesión en %s + Serás desconectado de todas las fuentes + Excluye manga NSFW del historial + Mostrar los números de páginas + Fuentes activadas + Fuentes disponibles + Informática… + Política de capturas de pantalla + Permitir + Bloquear siempre + Sugerencias + Activar sugerencias + Sugiere mangas según tus preferencias + Todos los datos sólo se analizan localmente en este dispositivo y nunca se envían a ninguna parte. + Empieza a leer manga y recibirás sugerencias personalizadas + No sugerir manga NSFW + Activado + Desactivado + No se puede cargar la lista de géneros + Bloqueo en NSFW + Conectado como %s + Selecciona los idiomas en los que quieres leer mangas. Puedes cambiarlo más tarde en los ajustes. + Reiniciar el filtro + Nunca + 18+ + Siempre + Precargar las páginas + Sólo en Wi-Fi + Varios idiomas + Buscar capítulo + No hay capítulos en este manga + %1$s%% + Aspecto + Actualización de las sugerencias + Excluir géneros + Especifica los géneros que no quieres ver en las sugerencias + Remoción completada + ¿Eliminar elementos seleccionados del dispositivo de forma permanente\? + Ocultar + Ralentización de la descarga + Nuevas fuentes de manga son disponibles + Ayuda a evitar el bloqueo de tu dirección IP + Procesamiento de manga guardado + Comprueba si hay nuevos capítulos y notifica sobre ellos + Recibirás notificaciones sobre las actualizaciones del manga que estés leyendo + Añadir marcador + Marcadores + Deshacer + Marcador eliminado + Eliminado del historial + Eliminar marcador + Añadido a favoritos + DNS mediante HTTPS + Modo predeterminado + Autodetectar modo de lectura + Detecta automáticamente si el manga es un webtoon + Los capítulos se eliminarán en segundo plano + No recibirás notificaciones, pero los nuevos capítulos aparecerán destacados en las listas + Activar las notificaciones + No hay categorías favoritas + Nombre + Editar + Editar categoría + Desactivar todo + Desactivar la optimización de la batería + Enviar + Algo ha ido mal. Por favor, envía un informe de errores a los desarrolladores para ayudarnos a solucionarlo. + Utilizar la huella dactilar si está disponible + Mangas de tus favoritos + Sus mangas recientemente leídos + Cerrar sesión + Planeado + Lectura + Abandonado + En espera + Informar + Seguimiento + Ayuda con las comprobaciones de las actualizaciones en segundo plano + Relectura + Completado + Mostrar indicadores de progreso en la lectura + Eliminación de datos + Mostrar porcentaje de lectura en el historial y en los favoritos + El manga marcado como NSFW nunca se añadirá al historial y no se guardará tu progreso + Puede ayudar en caso de algunos problemas. Todas las autorizaciones serán invalidadas + Mostrar todo + Dominio no válido + Encuentra qué leer en la sección «Explorar» + La cuenta ya existe + Sincronización + Introduce tu correo electrónico para continuar + Últimas 2 horas + Todavía no hay marcadores + Puedes crear marcadores mientras lees el manga + Marcadores eliminados + Habilitar las fuentes de manga para leer manga en línea + Aleatorio + Reordenar + Vacío + Otro caché + Uso del almacenamiento + Disponible + Eliminado de los favoritos + Opciones + Modo incógnito + No hay capítulos + Mostrar la barra de información en el lector + Importando el manga + Importación completada + La importación comenzará pronto + Cancelado + Atrás + Sincronizar tus datos + Tu manga se mostrará aquí + Borrar todo el historial + Sin fuentes de manga + Historial borrado + Gestionar + Pulsa de nuevo «Atrás» para salir + Carpeta con imágenes + ¿Estás seguro de que quieres eliminar las categorías favoritas seleccionadas\? \nTodos los mangas en ella se perderán y esto no se puede deshacer. - Explorar - %s - %s - Pulse dos veces «Atrás» para salir de la aplicación - Confirmación de salida - Caché de páginas - Cap.%1$d/%2$d Pg.%3$d/%4$d - Manga guardado - Desplazamiento automático - Archivo de cómics - Puedes eliminar el archivo original del almacenamiento para ahorrar espacio - Selecciona el rango - Contenido no encontrado o eliminado - Detalles del error:<br><tt>%1$s</tt><br><br>1. Intenta <a href=%2$s>abrir el manga en un navegador web</a> para asegurarte de que esté disponible en tu fuente<br>2. Asegúrete de estar utilizando la <a href=kotatsu://about>última versión de Kotatsu</a><br>3. Si está disponible, envía un informe de error a los desarrolladores. - Hacer que los mangas recientes estén disponibles mediante una pulsación larga en el icono de la aplicación - Los ajustes de color elegidos serán recordados para este manga - Fuente - Mostrar los accesos directos a los mangas recientes - Tocando el borde derecho o pulsando la tecla derecha se pasa siempre a la página siguiente - Control ergonómico del lector - Corrección del color - Brillo - Contraste - Restablecer - ¿Guardar o descartar los cambios no guardados\? - Descartar - Sin espacio en dispositivo - Zoom de webtoon - Mostrar el deslizador de cambio de página - Error del servidor (%1$d). Vuelva a intentarlo más tarde - Información clara sobre los nuevos capítulos - Diferentes idiomas - La red no está disponible - Compacta - Enciende la Wi-Fi o la red móvil para leer los mangas en línea - Fuente desactivada - Precargar el contenido - Marcar como actual - Idioma - Compartir los registros - Grabar algunas acciones para depurar - Activar el registro - Mostrar contenido sospechoso - Dinámico - Esquema de colores - Mostrar en vista de cuadrícula - Asuka - Mion - Rikka - Sakura - Miku - No hay nada aquí - Mamimi - Canadé - Para realizar un seguimiento del progreso de la lectura, seleccione Menú → Seguimiento en la pantalla de detalles del manga. - Servicios - Actualizaciones propuestas para las versiones beta de la aplicación - Permitir actualizaciones inestables - Descarga iniciada - Encabezado del agente de usuario - Por favor, reinicie la aplicación para aplicar estos cambios - Mantén pulsado un elemento para reordenarlos - Puedes seleccionar uno o más archivos .cbz o .zip, cada archivo será reconocido como un manga independiente. - Puedes seleccionar un directorio con unos archivos o imágenes. Cada archivo (o subdirectorio) se reconocerá como un capítulo. - Velocidad - Importar una copia de seguridad de los datos del usuario creada previamente - Mostrar en la estantería - Entendido - Puedes acceder a una cuenta existente o crear una nueva - Buscar similares - Parámetros de sincronización - Dirección del servidor - Ignorar los errores SSL - Elige un espejo automáticamente - Cambio automático de dominios para las fuentes remotas en caso de error si hay réplicas disponibles - Pausar - Reanudar - Eliminación completa - Cancelar todo - Descargar solo por WiFi - Detener la descarga al cambiar a una red móvil - Puedes utilizar un servidor de sincronización propio o uno predeterminado. No cambies esto si no estás seguro de lo que haces. - Pausado - Activar - No, gracias - No tienes descargas - Sugerencia: %s - Algunas veces muestra las notificaciones con el manga sugerido - Las descargas se han reanudado - Más - Todas las descargas activas se cancelarán, los datos descargados parcialmente se perderán - Tu historial de descargas se borrará permanentemente - Se han pausado las descargas - Las descargas se han eliminado - Las descargas se han cancelado - ¿Quieres recibir sugerencias sobre mangas personalizadas\? - Traducciones - WebView no está disponible: comprueba si el proveedor de WebView está instalado - Borrar la caché de la red - Tipo - Dirección - Puerto - Proxy - Valor no válido - %1$s (%2$s) - Optimización de imágenes proxy - Nombre de usuario - Descargado - Autorización (opcional) - Utiliza el servicio wsrv.nl para reducir el uso del tráfico y acelerar la carga de imágenes si es posible - Contraseña - Invertir los colores - \ No newline at end of file + Explorar + %s - %s + Pulse dos veces «Atrás» para salir de la aplicación + Confirmación de salida + Caché de páginas + Cap.%1$d/%2$d Pg.%3$d/%4$d + Manga guardado + Desplazamiento automático + Archivo de cómics + Puedes eliminar el archivo original del almacenamiento para ahorrar espacio + Selecciona el rango + Contenido no encontrado o eliminado + Detalles del error:<br><tt>%1$s</tt><br><br>1. Intenta <a href=%2$s>abrir el manga en un navegador web</a> para asegurarte de que esté disponible en tu fuente<br>2. Asegúrete de estar utilizando la <a href=kotatsu://about>última versión de Kotatsu</a><br>3. Si está disponible, envía un informe de error a los desarrolladores. + Hacer que los mangas recientes estén disponibles mediante una pulsación larga en el icono de la aplicación + Los ajustes de color elegidos serán recordados para este manga + Fuente + Mostrar los accesos directos a los mangas recientes + Tocando el borde derecho o pulsando la tecla derecha se pasa siempre a la página siguiente + Control ergonómico del lector + Corrección del color + Brillo + Contraste + Restablecer + ¿Guardar o descartar los cambios no guardados\? + Descartar + Sin espacio en dispositivo + Zoom de webtoon + Mostrar el deslizador de cambio de página + Error del servidor (%1$d). Vuelva a intentarlo más tarde + Información clara sobre los nuevos capítulos + Diferentes idiomas + La red no está disponible + Compacta + Enciende la Wi-Fi o la red móvil para leer los mangas en línea + Fuente desactivada + Precargar el contenido + Marcar como actual + Idioma + Compartir los registros + Grabar algunas acciones para depurar + Activar el registro + Mostrar contenido sospechoso + Dinámico + Esquema de colores + Mostrar en vista de cuadrícula + Asuka + Mion + Rikka + Sakura + Miku + No hay nada aquí + Mamimi + Canadé + Para realizar un seguimiento del progreso de la lectura, seleccione Menú → Seguimiento en la pantalla de detalles del manga. + Servicios + Actualizaciones propuestas para las versiones beta de la aplicación + Permitir actualizaciones inestables + Descarga iniciada + Encabezado del agente de usuario + Por favor, reinicie la aplicación para aplicar estos cambios + Mantén pulsado un elemento para reordenarlos + Puedes seleccionar uno o más archivos .cbz o .zip, cada archivo será reconocido como un manga independiente. + Puedes seleccionar un directorio con unos archivos o imágenes. Cada archivo (o subdirectorio) se reconocerá como un capítulo. + Velocidad + Importar una copia de seguridad de los datos del usuario creada previamente + Mostrar en la estantería + Entendido + Puedes acceder a una cuenta existente o crear una nueva + Buscar similares + Parámetros de sincronización + Dirección del servidor + Ignorar los errores SSL + Elige un espejo automáticamente + Cambio automático de dominios para las fuentes remotas en caso de error si hay réplicas disponibles + Pausar + Reanudar + Eliminación completa + Cancelar todo + Descargar solo por WiFi + Detener la descarga al cambiar a una red móvil + Puedes utilizar un servidor de sincronización propio o uno predeterminado. No cambies esto si no estás seguro de lo que haces. + Pausado + Activar + No, gracias + No tienes descargas + Sugerencia: %s + Algunas veces muestra las notificaciones con el manga sugerido + Las descargas se han reanudado + Más + Todas las descargas activas se cancelarán, los datos descargados parcialmente se perderán + Tu historial de descargas se borrará permanentemente + Se han pausado las descargas + Las descargas se han eliminado + Las descargas se han cancelado + ¿Quieres recibir sugerencias sobre mangas personalizadas\? + Traducciones + WebView no está disponible: comprueba si el proveedor de WebView está instalado + Borrar la caché de la red + Tipo + Dirección + Puerto + Proxy + Valor no válido + %1$s (%2$s) + Optimización de imágenes proxy + Nombre de usuario + Descargado + Autorización (opcional) + Utiliza el servicio wsrv.nl para reducir el uso del tráfico y acelerar la carga de imágenes si es posible + Contraseña + Invertir los colores + diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 5fbd3be45..9bf16d703 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -7,7 +7,6 @@ Käännös Käännä tämä sovellus Luku puuttuu - Tämä luku puuttuu laitteestasi. Lataa tai lue se verkossa. Jonossa Lue lisää Jotkin valmistajat voivat muuttaa järjestelmän käyttäytymistä, mikä voi keskeyttää taustatehtäviä. @@ -125,7 +124,6 @@ Vakio t|kt|Mt|Gt|Tt Tyhjennä sivujen välimuisti - Historia ja välimuisti Ei kuvausta Virheellinen tiedosto. Vain ZIP ja CBZ ovat tuettuja. Tätä toimintoa ei tueta @@ -216,7 +214,6 @@ Aina Ei koskaan Nollaa suodatin - Etsi genre Valitse kielet, joilla haluat lukea mangaa. Voit muuttaa sitä myöhemmin asetuksissa. Kirjautunut sisään nimellä %s 18+ @@ -225,7 +222,6 @@ Eri kieliä Ei lukuja tässä mangassa Ulkonäkö - Sisältö Ehdotukset päivitetään Määritä genret, joita et halua nähdä ehdotuksissa Sulje pois genrejä diff --git a/app/src/main/res/values-fil/plurals.xml b/app/src/main/res/values-fil/plurals.xml index a36324941..92ac9c5dc 100644 --- a/app/src/main/res/values-fil/plurals.xml +++ b/app/src/main/res/values-fil/plurals.xml @@ -4,10 +4,6 @@ %1$d aytem %1$d (na) aytem - - "Kabuuang %1$d pahina" - Kabuuang %1$d (na) pahina - %1$d minutong nakakalipas %1$d (na) minutong nakakalipas diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml index 75a3e1d2f..c139be816 100644 --- a/app/src/main/res/values-fil/strings.xml +++ b/app/src/main/res/values-fil/strings.xml @@ -1,415 +1,411 @@ - Na-update - Pinakabago - Maliwanag - Marka - Pansala - Tema - Madilim - Sundan ang sistema - May nangyaring error - Error sa network - Mga detalye - Mga kabanata - Listahan - Na-save - I-share ang larawan - Mag-angkat - Tanggalin - Hindi suportado ang operasyong ito - Pumili ng ZIP o CBZ file. - Kasaysayan at cache - Walang paglalarawan - Laki ng grid - Hanapin sa %s - Tanggalin ang manga - Permanenteng tanggalin ang \"%s\" sa device\? - Mga setting sa pagbasa - Magpalit ng (mga) pahina - Pindutan ng volume - Magpatuloy - I-clear ang cache ng mga thumbnail - Na-clear - Mga kilos lang - Available ang isang bagong bersyon ng app - Buksan sa web browser - Ang manga na ito ay may %s. I-save ang lahat ng ito\? - Mga abiso - %1$d ng %2$d sa - Mga bagong kabanata - Subukang i-reformulate ang query. - Ang iyong nabasa ay ipapakita dito - Ang iyong manga ay ipapakita dito - Mag-save muna ng isang bagay - I-save ito mula sa mga online na source o mag import ng mga file. - Istante - Animasyon ng pahina - Hindi magagamit - Walang available na storage - Iba pang storage - Tapos na - Lahat ng paborito - Walang laman ang kategorya - Basahin mamaya - Mga update - Mga resulta ng paghahanap - Laki: %s - I-clear ang feed ng mga update - Na-clear - Update - Ang pag update ng feed ay magsisimula sa lalong madaling panahon - Maghanap ng mga update - Ilagay ang password - Humingi ng password kapag sinimulan ang Kotatsu - Tungkol rito - Maghanap ng update - Kanan sa kaliwa - Bagong Kategorya - Pagkasyahin sa gitna - Panatilihin sa simula - Gumagamit ng mas kaunting power sa mga AMOLED na screen - I-backup at i-restore - Naibalik na - Naghahanda… - Hindi nahanap ang file - Maaari kang lumikha ng backup ng iyong kasaysayan at mga paborito at ibalik ito - Ngayon lang - Kahapon - Matagal na ang nakalipas - Ngayong araw - I-tap para subukang muli - Lutasin - Inalis ang lahat ng mga cookie - I-clear ang feed - Suriin ang mga bagong kabanata - Mag-sign in - Mag-sign in upang tingnan ang nilalamang ito - Default: %s - Susunod - Kumpirmahin - Ang password ay dapat na 4 na character o higit pa - Maligayang pagdating - Na-save ang backup - Magbasa pa - Kulang ang kabanata - Ang pag-log in sa %s ay hindi suportado - Mga genre - Patuloy - Default - Hindi isali ang NSFW manga mula sa kasaysayan - Mga pahinang may bilang - Patakaran sa screenshot - Payagan - Palaging i-block - Mga mungkahi - Paganahin ang mga mungkahi - Simulan ang pagbabasa ng manga at makakakuha ka ng mga personalized na mungkahi - Huwag magmungkahi ng NSFW manga - Pinagana - Maghanap ng genre - Pumili ng mga wika na gusto mong basahin ang manga. Maaari mo itong baguhin sa ibang pagkakataon sa mga setting. - Lokal na storage - Mga paborito - Kasaysayan - Mode na listahan - Detalyadong listahan - Grid - Mga setting - Mga source ng Manga - Naglo-load… - Isara - Walang nahanap - Tanggalin - Bagong Kategorya - Nabasa - Wala pang paborito - I-paborito ito - Idagdag - I-save - Ibahagi - Lumikha ng shortcut… - Ibahagi sa %s - Maghanap - Maghanap ng manga - Nagda-download… - Nagpoproseso… - Na-download - Mga download - Pangalan - Sikat - Mga pahina - I-clear ang kasaysayan - I-clear ang kasaysayan ng paghahanap - Bagong bersyon: %s - Hindi tumutugma sa mga password - I-clear ang mga cookie - I-clear ang page cache - I-save - I-download - Mga setting ng abiso - Tunog ng abiso - Mga paboritong kategorya - Tanggalin - Parang walang laman dito… - Hanapin kung ano ang babasahin sa side menu. - Hanapin kung ano ang babasahin sa seksyong «Mag-explore» - Kamakailan - Folder para sa mga download - I-save ang pahina - Natanggal ang \"%s\" sa lokal na storage - Wala pang kasaysayan - Permanenteng i-clear ang lahat ng kasaysayan ng pagbabasa\? - Huwag suriin - Ulitin ang password - Protektahan ang app - Maling password - Bersyon %s - Mode ng scale - Walang available na update - Baliktarin - Grupo - Tahimik - Pagkasyahin sa lapad - Itim - Lumikha ng data backup - Ibalik mula sa backup - Naibalik ang lahat ng data - Ang data ay naibalik, ngunit may mga error - Ang napiling pagsasaayos ay maaalala para sa manga na ito - Isalin ang app na ito - Awtorisado na - Kinakailangan ang CAPTCHA - I-clear nang permanente ang lahat ng update history\? - Maglagay ng password para simulan ang app - Ang ilang device ay may iba\'t ibang gawi ng system, na maaaring masira ang mga gawain sa background. - Nakapila na - I-download o basahin ang nawawalang kabanata online. - Mala-log out ka mula sa lahat ng source - Tapos na - Alisin ang lahat ng kamakailang query sa paghahanap nang permanente\? - Pagsasalin - I-block sa NSFW - Magmungkahi ng manga batay sa iyong mga kagustuhan - Ang lahat ng data ay lokal lamang na sinusuri sa device na ito at hindi kailanman ipinadala kahit saan. - Hindi pinagana - Hindi ma-load ang listahan ng mga genre - I-reset ang filter - Ang mga bagong kabanata ng iyong binabasa ay makikita dito - I-rotate ang screen - Pagkasyahin sa tangkad - Hindi kailanman - Sa Wi-Fi lang - Nagco-compute… - Kabanata %1$d ng %2$d - Subukan ulit - Pag-aayos ng order - I-clear - Mga taps ng gilid - Mga ginamit na source - Magagamit na mga source - Lagi na lang - I-preload ang mga pahina - Naka-log in bilang %s - Iba\'t ibang wika - Maghanap ng kabanata - %1$s%% - Hitsura - Hindi isali ang mga genre - Tukuyin ang mga genre na hindi mo nais na makita sa mga mungkahi - Nakumpleto na ang pagtanggal - Tumutulong na maiwasan ang pag-block ng iyong IP address - Naka-save na pagproseso ng manga - Mayroon nang account - Bumalik - Pag-synchronize - Ilagay ang iyong email upang magpatuloy - Itago - May mga bagong source ng manga - Hindi ka makakatanggap ng mga abiso ngunit ang mga bagong kabanata ay iha-highlight sa mga listahan - Paganahin ang mga abiso - Ayusin ang kategorya - Tina-track - Walang mga paboritong kategorya - Mag-log out - Magdagdag ng bookmark - Tinanggal ang bookmark - Inalis sa kasaysayan - DNS sa HTTPS - Default na mode - Automatikong matukoy ang reader mode - May nangyaring mali. Mangyaring magsumite ng isang bug report sa mga developer upang matulungan kaming ayusin ito. - Ipadala - Muling pagbabasa - Binitawan - Manga mula sa iyong mga paborito - Ang iyong kamakailang nabasa na manga - Pagtanggal ng data - Ipakita ang porsyento na nabasa sa kasaysayan at mga paborito - Ipakita lahat - Pumili ng saklaw - I-clear ang lahat ng kasaysayan - Maaari kang lumikha ng bookmark habang nagbabasa ng manga - Tinanggal ang mga bookmark - Random - Walang mga source ng manga - Paganahin ang mga source ng manga upang basahin ang manga online - Ayusin muli - Walang laman - Pindutin muli ang Bumalik upang lumabas - Pindutin ang Bumalik nang dalawang beses upang lumabas sa app - Pagkumpirma ng paglabas - Na-save na manga - Mag-Explore - Iba pang cache - Paggamit ng storage - Magagamit na - %s - %s - Inalis sa mga paborito - Mga pagpipilian - Incognito mode - Walang mga kabanata - Awtomatikong pag-scroll - Ch. %1$d/%2$d Pg. %3$d/%4$d - Ipakita ang information bar sa pagbasa - Archive ng mga comics - Folder na may mga larawan - Nakumpleto na ang pag-import - Magsisimula na ang pag-import - Feed - Gawing magagamit ang kamakailang manga sa pamamagitan ng mahabang pagpindot sa icon ng application - Ipakita ang mga kamakailang manga shortcut - Ergonomic na kontrol sa mambabasa - Pagwawasto ng kulay - Liwanag - Kaibahan - I-save o kalimutan ang mga hindi na-save na pagbabago\? - Kalimutan - Walang natitirang espasyo sa device - Pag-zoom sa webtoon - Iba\'t ibang wika - Server side error (%1$d). Subukang muli mamaya - I-clear din ang impormasyon tungkol sa mga bagong kabanata - Preloading ng nilalaman - Markahan bilang kasalukuyan - Wika - Ibahagi ang mga log - Magpakita ng kahina-hinalang nilalaman - Dynamic - Ipakita sa grid view - Asuka - Mion - Rikka - Sakura - Mamimi - Kanade - Wala naman dito - Mga serbisyo - Payagan ang mga hindi stable na update - Ipakita ang mga tagapagpahiwatig ng progress ng pagbabasa - Manga na minarkahan bilang NSFW ay hindi kailanman idadagdag sa kasaysayan at ang iyong progress ay hindi mase-save - Maaaring makatulong sa kaso ng ilang mga isyu. Ang lahat ng pahintulot ay mawawalan ng bisa - Imbalidong domain - Huling 2 oras - Nabura ang kasaysayan - Pamahalaan - Wala pang bookmark - 18+ - Hindi natagpuan o inalis ang nilalaman - Magtala ng ilang pagkilos para sa mga layunin ng pag-debug - Permanenteng tanggalin ang mga napiling item sa device\? - Walang mga kabanata sa manga na ito - Nag-a-update ang mga mungkahi - Nilalaman - Pagbagal ng pag-download - Tatanggalin ang mga kabanata sa background - Kinansela - I-sync ang iyong data - Tingnan ang mga bagong kabanata at ipaalam ang tungkol dito - Pangalan - I-edit - Tanggalin ang bookmark - Makakatanggap ka ng mga abiso tungkol sa mga update ng manga na iyong binabasa - Mag-undo - Nagbabasa - Cache ng mga pahina - Mga bookmark - Sigurado ka bang gusto mong tanggalin ang mga napiling paboritong kategorya\? + Na-update + Pinakabago + Maliwanag + Marka + Pansala + Tema + Madilim + Sundan ang sistema + May nangyaring error + Error sa network + Mga detalye + Mga kabanata + Listahan + Na-save + I-share ang larawan + Mag-angkat + Tanggalin + Hindi suportado ang operasyong ito + Pumili ng ZIP o CBZ file. + Walang paglalarawan + Laki ng grid + Hanapin sa %s + Tanggalin ang manga + Permanenteng tanggalin ang \"%s\" sa device\? + Mga setting sa pagbasa + Magpalit ng (mga) pahina + Pindutan ng volume + Magpatuloy + I-clear ang cache ng mga thumbnail + Na-clear + Mga kilos lang + Available ang isang bagong bersyon ng app + Buksan sa web browser + Ang manga na ito ay may %s. I-save ang lahat ng ito\? + Mga abiso + %1$d ng %2$d sa + Mga bagong kabanata + Subukang i-reformulate ang query. + Ang iyong nabasa ay ipapakita dito + Ang iyong manga ay ipapakita dito + Mag-save muna ng isang bagay + I-save ito mula sa mga online na source o mag import ng mga file. + Istante + Animasyon ng pahina + Hindi magagamit + Walang available na storage + Iba pang storage + Tapos na + Lahat ng paborito + Walang laman ang kategorya + Basahin mamaya + Mga update + Mga resulta ng paghahanap + Laki: %s + I-clear ang feed ng mga update + Na-clear + Update + Ang pag update ng feed ay magsisimula sa lalong madaling panahon + Maghanap ng mga update + Ilagay ang password + Humingi ng password kapag sinimulan ang Kotatsu + Tungkol rito + Maghanap ng update + Kanan sa kaliwa + Bagong Kategorya + Pagkasyahin sa gitna + Panatilihin sa simula + Gumagamit ng mas kaunting power sa mga AMOLED na screen + I-backup at i-restore + Naibalik na + Naghahanda… + Hindi nahanap ang file + Maaari kang lumikha ng backup ng iyong kasaysayan at mga paborito at ibalik ito + Ngayon lang + Kahapon + Matagal na ang nakalipas + Ngayong araw + I-tap para subukang muli + Lutasin + Inalis ang lahat ng mga cookie + I-clear ang feed + Suriin ang mga bagong kabanata + Mag-sign in + Mag-sign in upang tingnan ang nilalamang ito + Default: %s + Susunod + Kumpirmahin + Ang password ay dapat na 4 na character o higit pa + Maligayang pagdating + Na-save ang backup + Magbasa pa + Kulang ang kabanata + Ang pag-log in sa %s ay hindi suportado + Mga genre + Patuloy + Default + Hindi isali ang NSFW manga mula sa kasaysayan + Mga pahinang may bilang + Patakaran sa screenshot + Payagan + Palaging i-block + Mga mungkahi + Paganahin ang mga mungkahi + Simulan ang pagbabasa ng manga at makakakuha ka ng mga personalized na mungkahi + Huwag magmungkahi ng NSFW manga + Pinagana + Pumili ng mga wika na gusto mong basahin ang manga. Maaari mo itong baguhin sa ibang pagkakataon sa mga setting. + Lokal na storage + Mga paborito + Kasaysayan + Mode na listahan + Detalyadong listahan + Grid + Mga setting + Mga source ng Manga + Naglo-load… + Isara + Walang nahanap + Tanggalin + Bagong Kategorya + Nabasa + Wala pang paborito + I-paborito ito + Idagdag + I-save + Ibahagi + Lumikha ng shortcut… + Ibahagi sa %s + Maghanap + Maghanap ng manga + Nagda-download… + Nagpoproseso… + Na-download + Mga download + Pangalan + Sikat + Mga pahina + I-clear ang kasaysayan + I-clear ang kasaysayan ng paghahanap + Bagong bersyon: %s + Hindi tumutugma sa mga password + I-clear ang mga cookie + I-clear ang page cache + I-save + I-download + Mga setting ng abiso + Tunog ng abiso + Mga paboritong kategorya + Tanggalin + Parang walang laman dito… + Hanapin kung ano ang babasahin sa side menu. + Hanapin kung ano ang babasahin sa seksyong «Mag-explore» + Kamakailan + Folder para sa mga download + I-save ang pahina + Natanggal ang \"%s\" sa lokal na storage + Wala pang kasaysayan + Permanenteng i-clear ang lahat ng kasaysayan ng pagbabasa\? + Huwag suriin + Ulitin ang password + Protektahan ang app + Maling password + Bersyon %s + Mode ng scale + Walang available na update + Baliktarin + Grupo + Tahimik + Pagkasyahin sa lapad + Itim + Lumikha ng data backup + Ibalik mula sa backup + Naibalik ang lahat ng data + Ang data ay naibalik, ngunit may mga error + Ang napiling pagsasaayos ay maaalala para sa manga na ito + Isalin ang app na ito + Awtorisado na + Kinakailangan ang CAPTCHA + I-clear nang permanente ang lahat ng update history\? + Maglagay ng password para simulan ang app + Ang ilang device ay may iba\'t ibang gawi ng system, na maaaring masira ang mga gawain sa background. + Nakapila na + Mala-log out ka mula sa lahat ng source + Tapos na + Alisin ang lahat ng kamakailang query sa paghahanap nang permanente\? + Pagsasalin + I-block sa NSFW + Magmungkahi ng manga batay sa iyong mga kagustuhan + Ang lahat ng data ay lokal lamang na sinusuri sa device na ito at hindi kailanman ipinadala kahit saan. + Hindi pinagana + Hindi ma-load ang listahan ng mga genre + I-reset ang filter + Ang mga bagong kabanata ng iyong binabasa ay makikita dito + I-rotate ang screen + Pagkasyahin sa tangkad + Hindi kailanman + Sa Wi-Fi lang + Nagco-compute… + Kabanata %1$d ng %2$d + Subukan ulit + Pag-aayos ng order + I-clear + Mga taps ng gilid + Mga ginamit na source + Magagamit na mga source + Lagi na lang + I-preload ang mga pahina + Naka-log in bilang %s + Iba\'t ibang wika + Maghanap ng kabanata + %1$s%% + Hitsura + Hindi isali ang mga genre + Tukuyin ang mga genre na hindi mo nais na makita sa mga mungkahi + Nakumpleto na ang pagtanggal + Tumutulong na maiwasan ang pag-block ng iyong IP address + Naka-save na pagproseso ng manga + Mayroon nang account + Bumalik + Pag-synchronize + Ilagay ang iyong email upang magpatuloy + Itago + May mga bagong source ng manga + Hindi ka makakatanggap ng mga abiso ngunit ang mga bagong kabanata ay iha-highlight sa mga listahan + Paganahin ang mga abiso + Ayusin ang kategorya + Tina-track + Walang mga paboritong kategorya + Mag-log out + Magdagdag ng bookmark + Tinanggal ang bookmark + Inalis sa kasaysayan + DNS sa HTTPS + Default na mode + Automatikong matukoy ang reader mode + May nangyaring mali. Mangyaring magsumite ng isang bug report sa mga developer upang matulungan kaming ayusin ito. + Ipadala + Muling pagbabasa + Binitawan + Manga mula sa iyong mga paborito + Ang iyong kamakailang nabasa na manga + Pagtanggal ng data + Ipakita ang porsyento na nabasa sa kasaysayan at mga paborito + Ipakita lahat + Pumili ng saklaw + I-clear ang lahat ng kasaysayan + Maaari kang lumikha ng bookmark habang nagbabasa ng manga + Tinanggal ang mga bookmark + Random + Walang mga source ng manga + Paganahin ang mga source ng manga upang basahin ang manga online + Ayusin muli + Walang laman + Pindutin muli ang Bumalik upang lumabas + Pindutin ang Bumalik nang dalawang beses upang lumabas sa app + Pagkumpirma ng paglabas + Na-save na manga + Mag-Explore + Iba pang cache + Paggamit ng storage + Magagamit na + %s - %s + Inalis sa mga paborito + Mga pagpipilian + Incognito mode + Walang mga kabanata + Awtomatikong pag-scroll + Ch. %1$d/%2$d Pg. %3$d/%4$d + Ipakita ang information bar sa pagbasa + Archive ng mga comics + Folder na may mga larawan + Nakumpleto na ang pag-import + Magsisimula na ang pag-import + Feed + Gawing magagamit ang kamakailang manga sa pamamagitan ng mahabang pagpindot sa icon ng application + Ipakita ang mga kamakailang manga shortcut + Ergonomic na kontrol sa mambabasa + Pagwawasto ng kulay + Liwanag + Kaibahan + I-save o kalimutan ang mga hindi na-save na pagbabago\? + Kalimutan + Walang natitirang espasyo sa device + Pag-zoom sa webtoon + Iba\'t ibang wika + Server side error (%1$d). Subukang muli mamaya + I-clear din ang impormasyon tungkol sa mga bagong kabanata + Preloading ng nilalaman + Markahan bilang kasalukuyan + Wika + Ibahagi ang mga log + Magpakita ng kahina-hinalang nilalaman + Dynamic + Ipakita sa grid view + Asuka + Mion + Rikka + Sakura + Mamimi + Kanade + Wala naman dito + Mga serbisyo + Payagan ang mga hindi stable na update + Ipakita ang mga tagapagpahiwatig ng progress ng pagbabasa + Manga na minarkahan bilang NSFW ay hindi kailanman idadagdag sa kasaysayan at ang iyong progress ay hindi mase-save + Maaaring makatulong sa kaso ng ilang mga isyu. Ang lahat ng pahintulot ay mawawalan ng bisa + Imbalidong domain + Huling 2 oras + Nabura ang kasaysayan + Pamahalaan + Wala pang bookmark + 18+ + Hindi natagpuan o inalis ang nilalaman + Magtala ng ilang pagkilos para sa mga layunin ng pag-debug + Permanenteng tanggalin ang mga napiling item sa device\? + Walang mga kabanata sa manga na ito + Nag-a-update ang mga mungkahi + Pagbagal ng pag-download + Tatanggalin ang mga kabanata sa background + Kinansela + I-sync ang iyong data + Tingnan ang mga bagong kabanata at ipaalam ang tungkol dito + Pangalan + I-edit + Tanggalin ang bookmark + Makakatanggap ka ng mga abiso tungkol sa mga update ng manga na iyong binabasa + Mag-undo + Nagbabasa + Cache ng mga pahina + Mga bookmark + Sigurado ka bang gusto mong tanggalin ang mga napiling paboritong kategorya\? \nAng lahat ng manga sa loob nito ay mawawala at hindi na ito mababawi. - Idinagdag ang bookmark - Awtomatikong matukoy kung ang manga ay webtoon - Huwag paganahin ang pag-optimize ng baterya - Tumutulong sa mga pagsusuri sa mga update sa background - Nakaplano - Nakumpleto na - Naka-hold - Huwag paganahin ang lahat - Gumamit ng fingerprint kung magagamit - Ulat - I-reset - Magmungkahi ng mga update sa mga beta na bersyon ng app - Hindi magagamit ang network - I-on ang Wi-Fi o mobile network para magbasa ng manga online - Mag-tap sa kanang gilid o ang pagpindot sa kanang key ay palaging lilipat sa susunod na pahina - Ipakita ang slider ng paglipat ng pahina - Mga detalye ng error:<br><tt>%1$s</tt><br><br>1. Subukang <a href=%2$s>magbukas ng manga sa isang web browser</a> upang matiyak na available ito sa souce<br>2. Tiyaking ginagamit mo ang <a href=kotatsu://about>pinakabagong bersyon ng Kotatsu</a><br>3. Kung available ito, magpadala ng ulat ng error sa mga developer. - Paganahin ang pag-log - Hindi pinagana ang source - Pag-import ng manga - Maaari mong tanggalin ang orihinal na file mula sa storage upang makatipid ng espasyo - Ang napiling mga setting ng kulay ay matatandaan para sa manga na ito - Compact - Upang subaybayan ang pag unlad ng pagbabasa, piliin ang Menu → Track sa screen ng mga detalye ng manga. - Nagsimula na ang pag-download - Scheme ng kulay - Miku - Header ng UserAgent - B|kB|MB|GB|TB - Standard - Webtoon - Read mode - Error - Internal storage - External storage - Vibration - Domain - LED indicator - Mangyaring i-restart ang application upang ilapat ang mga pagbabagong ito - Nakuha ko - I-tap at hawakan ang isang aytem upang muling ayusin ang mga ito - Mag-import ng dating ginawa na backup ng data ng user - Ipakita sa Istante - Bilis - Maaari kang pumili ng isa o higit pang .cbz o .zip file, ang bawat file ay makikilala bilang isang hiwalay na manga. - Maaari kang pumili ng isang directory na may mga archive o mga larawan. Ang bawat archive (o subdirectory) ay makikilala bilang isang kabanata. - Maghanap ng katulad - Maaari kang mag-sign in sa isang umiiral na account o lumikha ng bago - Mga pagsasalin - Hindi available ang WebView: tingnan kung naka-install ang WebView provider - Paganahin - Na-pause ang mga pag-download - Mga setting ng pag-synchronize - Address ng server - Maaari kang gumamit ng self-hosted synchronization server o isang default. Huwag baguhin ito kung hindi ka sigurado sa iyong ginagawa. - Huwag pansinin ang mga error sa SSL - Awtomatikong pumili ng mirror - Awtomatikong lumipat ng mga domain para sa mga remote source sa mga error kung available ang mga mirror - Kanselahin lahat - Mag-download lamang sa pamamagitan ng Wi-Fi - Itigil ang pag-download kapag lumipat sa isang mobile network - Naka-pause - Tanggalin ang nakumpleto na - Mga mungkahi: %s - I-pause - Minsang magpakita ng mga notification na may iminungkahing manga - Higit pa - Salamat nalang - Ipagpatuloy - Ang lahat ng mga aktibong pag download ay kakanselahin, bahagyang na download na data ay mawawala - Permanenteng ide-delete ang iyong history ng mga pag-download - Wala kang anumang mga pag-download - Ipinagpatuloy ang mga pag-download - Gusto mo bang makatanggap ng personalized na mga mungkahi sa manga\? - Inalis na ang mga download - Nakansela ang mga pag-download - \ No newline at end of file + Idinagdag ang bookmark + Awtomatikong matukoy kung ang manga ay webtoon + Huwag paganahin ang pag-optimize ng baterya + Tumutulong sa mga pagsusuri sa mga update sa background + Nakaplano + Nakumpleto na + Naka-hold + Huwag paganahin ang lahat + Gumamit ng fingerprint kung magagamit + Ulat + I-reset + Magmungkahi ng mga update sa mga beta na bersyon ng app + Hindi magagamit ang network + I-on ang Wi-Fi o mobile network para magbasa ng manga online + Mag-tap sa kanang gilid o ang pagpindot sa kanang key ay palaging lilipat sa susunod na pahina + Ipakita ang slider ng paglipat ng pahina + Mga detalye ng error:<br><tt>%1$s</tt><br><br>1. Subukang <a href=%2$s>magbukas ng manga sa isang web browser</a> upang matiyak na available ito sa souce<br>2. Tiyaking ginagamit mo ang <a href=kotatsu://about>pinakabagong bersyon ng Kotatsu</a><br>3. Kung available ito, magpadala ng ulat ng error sa mga developer. + Paganahin ang pag-log + Hindi pinagana ang source + Pag-import ng manga + Maaari mong tanggalin ang orihinal na file mula sa storage upang makatipid ng espasyo + Ang napiling mga setting ng kulay ay matatandaan para sa manga na ito + Compact + Upang subaybayan ang pag unlad ng pagbabasa, piliin ang Menu → Track sa screen ng mga detalye ng manga. + Nagsimula na ang pag-download + Scheme ng kulay + Miku + Header ng UserAgent + B|kB|MB|GB|TB + Standard + Webtoon + Read mode + Error + Internal storage + External storage + Vibration + Domain + LED indicator + Mangyaring i-restart ang application upang ilapat ang mga pagbabagong ito + Nakuha ko + I-tap at hawakan ang isang aytem upang muling ayusin ang mga ito + Mag-import ng dating ginawa na backup ng data ng user + Ipakita sa Istante + Bilis + Maaari kang pumili ng isa o higit pang .cbz o .zip file, ang bawat file ay makikilala bilang isang hiwalay na manga. + Maaari kang pumili ng isang directory na may mga archive o mga larawan. Ang bawat archive (o subdirectory) ay makikilala bilang isang kabanata. + Maghanap ng katulad + Maaari kang mag-sign in sa isang umiiral na account o lumikha ng bago + Mga pagsasalin + Hindi available ang WebView: tingnan kung naka-install ang WebView provider + Paganahin + Na-pause ang mga pag-download + Mga setting ng pag-synchronize + Address ng server + Maaari kang gumamit ng self-hosted synchronization server o isang default. Huwag baguhin ito kung hindi ka sigurado sa iyong ginagawa. + Huwag pansinin ang mga error sa SSL + Awtomatikong pumili ng mirror + Awtomatikong lumipat ng mga domain para sa mga remote source sa mga error kung available ang mga mirror + Kanselahin lahat + Mag-download lamang sa pamamagitan ng Wi-Fi + Itigil ang pag-download kapag lumipat sa isang mobile network + Naka-pause + Tanggalin ang nakumpleto na + Mga mungkahi: %s + I-pause + Minsang magpakita ng mga notification na may iminungkahing manga + Higit pa + Salamat nalang + Ipagpatuloy + Ang lahat ng mga aktibong pag download ay kakanselahin, bahagyang na download na data ay mawawala + Permanenteng ide-delete ang iyong history ng mga pag-download + Wala kang anumang mga pag-download + Ipinagpatuloy ang mga pag-download + Gusto mo bang makatanggap ng personalized na mga mungkahi sa manga\? + Inalis na ang mga download + Nakansela ang mga pag-download + diff --git a/app/src/main/res/values-fr/plurals.xml b/app/src/main/res/values-fr/plurals.xml index c0da2ac13..a7bf3bfc0 100644 --- a/app/src/main/res/values-fr/plurals.xml +++ b/app/src/main/res/values-fr/plurals.xml @@ -1,38 +1,33 @@ - - Il y a %1$d minute - Il y a %1$d minutes - Il y a %1$d minutes - - - %1$d page au total - %1$d pages au total - %1$d pages au total - - - %1$d élément - %1$d éléments - %1$d éléments - - - %1$d nouveau chapitre - %1$d nouveaux chapitres - %1$d nouveaux chapitres - - - %1$d chapitre - %1$d chapitres - %1$d chapitres - - - Il y a %1$d heure - Il y a %1$d heures - Il y a %1$d heures - - - Il y a %1$d jour - Il y a %1$d jours - Il y a %1$d jours - - \ No newline at end of file + + Il y a %1$d minute + Il y a %1$d minutes + Il y a %1$d minutes + + + %1$d élément + %1$d éléments + %1$d éléments + + + %1$d nouveau chapitre + %1$d nouveaux chapitres + %1$d nouveaux chapitres + + + %1$d chapitre + %1$d chapitres + %1$d chapitres + + + Il y a %1$d heure + Il y a %1$d heures + Il y a %1$d heures + + + Il y a %1$d jour + Il y a %1$d jours + Il y a %1$d jours + + diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 04f0ee800..cfe28f185 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,429 +1,425 @@ - Lire la suite - Certains appareils ont un comportement différent du système, ce qui peut interrompre les tâches d\'arrière-plan. - Sauvegarde enregistrée - Bienvenue - Supprimer définitivement toutes les requêtes de recherche récentes \? - Le mot de passe doit comporter 4 caractères ou plus - Confirmer - Entrez un mot de passe pour démarrer l\'application avec - Suivant - Par défaut : %s - Connectez-vous pour voir ce contenu - Se connecter - Inverser - À la recherche de nouveaux chapitres - Effacer définitivement l\'historique des mises à jour \? - Effacer le flux - Tous les cookies ont été retirés - Effacer les cookies - Résoudre - CAPTCHA requis - Silencieux - On se souviendra de la configuration choisie pour ce manga - Appuyez pour réessayer - Aujourd\'hui - Groupe - Il y a longtemps - Hier - À l\'instant - Vous pouvez créer une sauvegarde de votre historique et de vos favoris et la restaurer - Les données ont été restaurées, mais il y a des erreurs - Toutes les données ont été restaurées - Fichier introuvable - Préparation… - Restauré - Restaurer à partir d\'une sauvegarde - Créer une sauvegarde des données - Sauvegarde et restauration - Utilise moins d\'énergie pour les écrans AMOLED - Noir - Garder au début - Ajuster à la largeur - Ajuster à la hauteur - Ajuster au centre - Mode mise à l\'échelle - Nouvelle catégorie - De droite à gauche - Aucune mise à jour disponible - Vérifier les mises à jour - Version %s - À propos - Les mots de passe ne correspondent pas - Répéter le mot de passe - Demander le mot de passe au démarrage de Kotatsu - Protéger l\'application - Mot de passe erroné - Entrez le mot de passe - Ne pas vérifier - Rechercher les mises à jour - La mise à jour des flux commencera bientôt - Mettre à Jour - Faire pivoter l\'écran - Effacé - Effacer le flux des mises à jour - Taille : %s - Nouvelle version : %s - Résultats de la recherche - Les nouveaux chapitres de ce que vous lisez sont présentés ici - Mises à jour - Lire plus tard - Catégorie vide - Tous les favoris - Terminé - Autre stockage - Pas de stockage disponible - Non disponible - Dossier pour les téléchargements - Animation de page - Récents - Étagère - Enregistrez-le à partir de sources en ligne ou importez des fichiers. - Sauvegardez d\'abord quelque chose - Trouvez ce que vous voulez lire dans le menu latéral. - Ce que vous lisez sera affiché ici - Essayez de reformuler la requête. - C\'est un peu vide ici… - Retirer - Catégories favorites - Vibration - Indicateur lumineux - Son de notification - Paramètres des notifications - Télécharger - Nouveaux chapitres - %1$d de %2$d activé(s) - Notifications - Ce manga a %s. Tout sauvegarder \? - Enregistrer - Ouvrir dans le navigateur - Une nouvelle version de l\'application est disponible - Domaine - Stockage externe - Stockage interne - Gestes uniquement - Effacé - Effacer l\'historique de recherche - Vider le cache des miniatures - Erreur - Continuer - Boutons de volume - Appuis au bord - Changer de pages - Paramètres du lecteur - Supprimer « %s » de l\'appareil de façon permanente \? - Supprimer le manga - Rechercher sur %s - Taille de la grille - Mode lecture - Webtoon - Standard - o|ko|Mo|Go|To - Vider le cache de la page - Historique et cache - Aucune description - Choisissez un fichier ZIP ou CBZ. - Cette opération n\'est pas prise en charge - Supprimer - Importer - Partager l\'image - Sauvegardé - Sauvegarder la page - « %s » supprimé du stockage local - Retirer - Effacer définitivement l\'historique de lecture \? - Effacer - Pages - Suivre le système - Sombre - Clair - Thème - Filtre - Ordre de tri - Évaluation - Le plus récent - Mis à jour - Populaire - Nom - Téléchargements - Téléchargé - Traitement… - Téléchargement… - Rechercher un manga - Rechercher - Partager %s - Créer un raccourci… - Partager - Enregistrer - Ajouter - Nouvelle catégorie - Ajouter aux favoris - Aucun favori pour le moment - Lire - Pas encore d\'historique - Rien n\'a été trouvé - Effacer l\'historique - Réessayer - Fermer - Chapitre %1$d sur %2$d - Chargement… - Sources des mangas - Paramètres - Mode liste - Grille - Liste détaillée - Liste - Chapitres - Détails - Erreur réseau - Une erreur s\'est produite - Historique - Favoris - Stockage local - Le chapitre est manquant - Téléchargez ou lisez ce chapitre manquant en ligne. - En file d\'attente - Traduction - Traduire cette application - Genres - Vous serez déconnecté de toutes les sources - La connexion sur %s n\'est pas prise en charge - Autorisé - Terminé - En cours - Par défaut - Exclure les mangas osés de l\'historique - Pages numérotées - Sources utilisées - Sources disponibles - Calcul… - Bloquer pour contenu sensible - Toujours bloquer - Politique relative aux captures d\'écran - Autoriser - Suggestions - Ne pas suggérer de mangas osés - Activer les suggestions - Suggérer des mangas en fonction de vos préférences - Toutes les données sont analysées localement sur cet appareil et ne sont jamais envoyées ailleurs. - Commencez à lire des mangas et vous recevrez des suggestions personnalisées - Impossible de charger la liste des genres - Activé - Désactivé - Uniquement en Wi-Fi - Toujours - Précharger les pages - Trouver le genre - Jamais - Réinitialiser le filtre - Sélectionnez les langues dans lesquelles vous souhaitez lire les mangas. Vous pouvez le changer plus tard dans les paramètres. - Connecté en tant que %s - 18+ - Langues diverses - Trouver un chapitre - Pas de chapitres dans ce manga - %1$s%% - Apparence - Contenu - Mise à jour des suggestions - Exclure des genres - Spécifiez les genres que vous ne voulez pas voir apparaître dans les suggestions - Supprimer définitivement les éléments sélectionnés de l\'appareil \? - Suppression terminée - Ralentissement du téléchargement - Permet d\'éviter le blocage de votre adresse IP - Les chapitres seront supprimés en arrière-plan - Traitement des mangas sauvegardés - Masquer - De nouvelles sources de mangas sont disponibles - Vérifier les nouveaux chapitres et les notifier - Activer les notifications - Vous recevrez des notifications sur les mises à jour des mangas que vous lisez - Vous ne recevrez pas de notifications mais les nouveaux chapitres seront mis en évidence dans les listes - Pas de catégories préférées - Nom - Modifier - Modifier la catégorie - Ajouter un marque-page - Retirer le marque-page - Marque-pages - Marque-page ajouté - Marque-page retiré - Annuler - Retiré de l\'historique - DNS sur HTTPS - Mode par défaut - Mode de détection automatique du lecteur - Détecter automatiquement si un manga est un webtoon - Désactiver l\'optimisation de la batterie - Aide à la vérification des mises à jour des antécédents - Un problème est survenu. Veuillez soumettre un rapport de bogue aux développeurs pour nous aider à le corriger. - Envoyer - Tout désactiver - Utiliser l\'empreinte digitale si elle est disponible - Vos mangas récemment lus - Les mangas de vos favoris - Signaler - Suivi - Planifié - Lecture - Afficher les indicateurs de progression de lecture - Afficher le pourcentage de lecture dans l\'historique et les favoris - Les mangas marqués comme étant pour adultes ne seront jamais ajoutés à l\'historique et votre progression ne sera pas sauvegardée - Peut aider en cas de problème. Toutes les autorisations seront invalidées - Tout afficher - En attente - Abandonné - Suppression des données - Se déconnecter - Terminé - Relecture - Domaine invalide - Sélectionner une plage - Contenu non trouvé ou supprimé - Détails de l\'erreur:<br><tt>%1$s</tt><br><br>1. Essayez d\'<a href=%2$s>ouvrir le manga dans un navigateur web</a> pour vous assurer qu\'il est disponible sur sa source<br>2. Assurez-vous que vous utilisez la <a href=kotatsu://about>dernière version de Kotatsu</a><br>3. Si elle est disponible, envoyez un rapport d\'erreur aux développeurs. - Rappuyez sur Retour pour quitter - Êtes-vous sûr·e de vouloir supprimer les catégories de favoris sélectionnées \? + Lire la suite + Certains appareils ont un comportement différent du système, ce qui peut interrompre les tâches d\'arrière-plan. + Sauvegarde enregistrée + Bienvenue + Supprimer définitivement toutes les requêtes de recherche récentes \? + Le mot de passe doit comporter 4 caractères ou plus + Confirmer + Entrez un mot de passe pour démarrer l\'application avec + Suivant + Par défaut : %s + Connectez-vous pour voir ce contenu + Se connecter + Inverser + À la recherche de nouveaux chapitres + Effacer définitivement l\'historique des mises à jour \? + Effacer le flux + Tous les cookies ont été retirés + Effacer les cookies + Résoudre + CAPTCHA requis + Silencieux + On se souviendra de la configuration choisie pour ce manga + Appuyez pour réessayer + Aujourd\'hui + Groupe + Il y a longtemps + Hier + À l\'instant + Vous pouvez créer une sauvegarde de votre historique et de vos favoris et la restaurer + Les données ont été restaurées, mais il y a des erreurs + Toutes les données ont été restaurées + Fichier introuvable + Préparation… + Restauré + Restaurer à partir d\'une sauvegarde + Créer une sauvegarde des données + Sauvegarde et restauration + Utilise moins d\'énergie pour les écrans AMOLED + Noir + Garder au début + Ajuster à la largeur + Ajuster à la hauteur + Ajuster au centre + Mode mise à l\'échelle + Nouvelle catégorie + De droite à gauche + Aucune mise à jour disponible + Vérifier les mises à jour + Version %s + À propos + Les mots de passe ne correspondent pas + Répéter le mot de passe + Demander le mot de passe au démarrage de Kotatsu + Protéger l\'application + Mot de passe erroné + Entrez le mot de passe + Ne pas vérifier + Rechercher les mises à jour + La mise à jour des flux commencera bientôt + Mettre à Jour + Faire pivoter l\'écran + Effacé + Effacer le flux des mises à jour + Taille : %s + Nouvelle version : %s + Résultats de la recherche + Les nouveaux chapitres de ce que vous lisez sont présentés ici + Mises à jour + Lire plus tard + Catégorie vide + Tous les favoris + Terminé + Autre stockage + Pas de stockage disponible + Non disponible + Dossier pour les téléchargements + Animation de page + Récents + Étagère + Enregistrez-le à partir de sources en ligne ou importez des fichiers. + Sauvegardez d\'abord quelque chose + Trouvez ce que vous voulez lire dans le menu latéral. + Ce que vous lisez sera affiché ici + Essayez de reformuler la requête. + C\'est un peu vide ici… + Retirer + Catégories favorites + Vibration + Indicateur lumineux + Son de notification + Paramètres des notifications + Télécharger + Nouveaux chapitres + %1$d de %2$d activé(s) + Notifications + Ce manga a %s. Tout sauvegarder \? + Enregistrer + Ouvrir dans le navigateur + Une nouvelle version de l\'application est disponible + Domaine + Stockage externe + Stockage interne + Gestes uniquement + Effacé + Effacer l\'historique de recherche + Vider le cache des miniatures + Erreur + Continuer + Boutons de volume + Appuis au bord + Changer de pages + Paramètres du lecteur + Supprimer « %s » de l\'appareil de façon permanente \? + Supprimer le manga + Rechercher sur %s + Taille de la grille + Mode lecture + Webtoon + Standard + o|ko|Mo|Go|To + Vider le cache de la page + Aucune description + Choisissez un fichier ZIP ou CBZ. + Cette opération n\'est pas prise en charge + Supprimer + Importer + Partager l\'image + Sauvegardé + Sauvegarder la page + « %s » supprimé du stockage local + Retirer + Effacer définitivement l\'historique de lecture \? + Effacer + Pages + Suivre le système + Sombre + Clair + Thème + Filtre + Ordre de tri + Évaluation + Le plus récent + Mis à jour + Populaire + Nom + Téléchargements + Téléchargé + Traitement… + Téléchargement… + Rechercher un manga + Rechercher + Partager %s + Créer un raccourci… + Partager + Enregistrer + Ajouter + Nouvelle catégorie + Ajouter aux favoris + Aucun favori pour le moment + Lire + Pas encore d\'historique + Rien n\'a été trouvé + Effacer l\'historique + Réessayer + Fermer + Chapitre %1$d sur %2$d + Chargement… + Sources des mangas + Paramètres + Mode liste + Grille + Liste détaillée + Liste + Chapitres + Détails + Erreur réseau + Une erreur s\'est produite + Historique + Favoris + Stockage local + Le chapitre est manquant + En file d\'attente + Traduction + Traduire cette application + Genres + Vous serez déconnecté de toutes les sources + La connexion sur %s n\'est pas prise en charge + Autorisé + Terminé + En cours + Par défaut + Exclure les mangas osés de l\'historique + Pages numérotées + Sources utilisées + Sources disponibles + Calcul… + Bloquer pour contenu sensible + Toujours bloquer + Politique relative aux captures d\'écran + Autoriser + Suggestions + Ne pas suggérer de mangas osés + Activer les suggestions + Suggérer des mangas en fonction de vos préférences + Toutes les données sont analysées localement sur cet appareil et ne sont jamais envoyées ailleurs. + Commencez à lire des mangas et vous recevrez des suggestions personnalisées + Impossible de charger la liste des genres + Activé + Désactivé + Uniquement en Wi-Fi + Toujours + Précharger les pages + Jamais + Réinitialiser le filtre + Sélectionnez les langues dans lesquelles vous souhaitez lire les mangas. Vous pouvez le changer plus tard dans les paramètres. + Connecté en tant que %s + 18+ + Langues diverses + Trouver un chapitre + Pas de chapitres dans ce manga + %1$s%% + Apparence + Mise à jour des suggestions + Exclure des genres + Spécifiez les genres que vous ne voulez pas voir apparaître dans les suggestions + Supprimer définitivement les éléments sélectionnés de l\'appareil \? + Suppression terminée + Ralentissement du téléchargement + Permet d\'éviter le blocage de votre adresse IP + Les chapitres seront supprimés en arrière-plan + Traitement des mangas sauvegardés + Masquer + De nouvelles sources de mangas sont disponibles + Vérifier les nouveaux chapitres et les notifier + Activer les notifications + Vous recevrez des notifications sur les mises à jour des mangas que vous lisez + Vous ne recevrez pas de notifications mais les nouveaux chapitres seront mis en évidence dans les listes + Pas de catégories préférées + Nom + Modifier + Modifier la catégorie + Ajouter un marque-page + Retirer le marque-page + Marque-pages + Marque-page ajouté + Marque-page retiré + Annuler + Retiré de l\'historique + DNS sur HTTPS + Mode par défaut + Mode de détection automatique du lecteur + Détecter automatiquement si un manga est un webtoon + Désactiver l\'optimisation de la batterie + Aide à la vérification des mises à jour des antécédents + Un problème est survenu. Veuillez soumettre un rapport de bogue aux développeurs pour nous aider à le corriger. + Envoyer + Tout désactiver + Utiliser l\'empreinte digitale si elle est disponible + Vos mangas récemment lus + Les mangas de vos favoris + Signaler + Suivi + Planifié + Lecture + Afficher les indicateurs de progression de lecture + Afficher le pourcentage de lecture dans l\'historique et les favoris + Les mangas marqués comme étant pour adultes ne seront jamais ajoutés à l\'historique et votre progression ne sera pas sauvegardée + Peut aider en cas de problème. Toutes les autorisations seront invalidées + Tout afficher + En attente + Abandonné + Suppression des données + Se déconnecter + Terminé + Relecture + Domaine invalide + Sélectionner une plage + Contenu non trouvé ou supprimé + Détails de l\'erreur:<br><tt>%1$s</tt><br><br>1. Essayez d\'<a href=%2$s>ouvrir le manga dans un navigateur web</a> pour vous assurer qu\'il est disponible sur sa source<br>2. Assurez-vous que vous utilisez la <a href=kotatsu://about>dernière version de Kotatsu</a><br>3. Si elle est disponible, envoyez un rapport d\'erreur aux développeurs. + Rappuyez sur Retour pour quitter + Êtes-vous sûr·e de vouloir supprimer les catégories de favoris sélectionnées \? \nTous les mangas qui s\'y trouvent seront perdus et ceci ne peut pas être annulé. - Appuyez deux fois sur la touche Retour pour quitter l\'appli - Disponible - Confirmation de sortie - %s - %s - Flux - Importation de mangas - Retiré des favoris - Effacer tout l\'historique - Les 2 dernières heures - Historique effacé - Gérer - Aucun marque-page - Vous pouvez créer un marque-page pendant la lecture d\'un manga - Marque-pages supprimés - Aucune source de mangas - Autoriser les sources de mangas de lire des mangas en ligne - Aléatoire - Réordonner - Vide - Explorer - Vos mangas seront affichés ici - Trouvez ce que vous voulez lire dans la section « Explorer » - Annulé - Le compte existe déjà - Retour - Synchronisation - Synchronisez vos données - Entrez votre courriel pour continuer - Mangas sauvegardés - Cache des pages - Autre cache - Utilisation du stockage - Options - Mode incognito - Aucun chapitre - Défilement automatique - Ch. %1$d/%2$d Pg. %3$d/%4$d - Afficher la barre d\'infos dans le lecteur - Archives des BD - Dossier avec des images - Importation terminée - Vous pouvez supprimer le fichier original du stockage pour gagner de l\'espace - L\'importation va bientôt commencer - Sauvegarde ou abandon des modifications non sauvegardées \? - Abandonner - Rendre les mangas récents disponibles en appuyant longuement sur l\'icône de l\'application - Taper sur le bord droit ou appuyer sur la touche droite permet toujours de passer à la page suivante - Contrôle ergonomique du lecteur - Afficher les raccourcis des mangas récents - Correction des couleurs - Luminosité - Contraste - Réinitialiser - Les paramètres de couleurs choisis seront sauvegardés pour ce manga - Il n\'y a plus d\'espace sur l\'appareil - Afficher le curseur de changement de page - Zoom Webtoon - Activez le Wi-Fi ou le réseau mobile pour lire les mangas en ligne - Différentes langues - Le réseau n\'est pas disponible - Compact - Erreur côté serveur (%1$d). Veuillez réessayer plus tard - Effacer aussi les informations sur les nouveaux chapitres - Source désactivée - Préchargement du contenu - Marquer comme actuel - Partager les journaux - Activer la journalisation - Enregistrer certaines actions à des fins de débogage - Langue - Afficher le contenu suspect - Dynamique - Schéma de couleurs - Afficher en vue grille - Pour suivre la progression de la lecture, sélectionnez Menu → Suivre sur l\'écran des détails du manga. - Prestations de service - Il n\'y a rien ici - Sakura - Rikka - Miku - Asuka - Mion - Mamimi - Autoriser les mises à jour instables - Téléchargement commencé - Kanade - Proposer des mises à jour des versions bêta de l\'application - En-tête UserAgent - Veuillez redémarrer l\'application pour appliquer ces changements - Compris - Vitesse - Importer une sauvegarde des données de l\'utilisateur créée précédemment - Vous pouvez sélectionner un répertoire contenant des archives ou des images. Chaque archive (ou sous-répertoire) sera reconnue comme un chapitre. - Vous pouvez sélectionner un ou plusieurs fichiers .cbz ou .zip, chaque fichier sera reconnu comme un manga séparé. - Afficher sur l\'étagère - Appuyez sur un élément et maintenez-le enfoncé pour le réorganiser - Trouver des similaires - Arrêter le téléchargement lors du passage à un réseau mobile - Vous pouvez vous connecter à un compte existant ou en créer un nouveau - Adresse du serveur - Vous pouvez utiliser un serveur de synchronisation autohébergé ou un serveur par défaut. Ne modifiez pas ce paramètre si vous n\'êtes pas sûr·e de ce que vous faites. - Retrait terminé - Activer - Non merci - Paramètres de synchronisation - Ignorer les erreurs SSL - Choisir le miroir automatiquement - Changement automatique de domaine pour les sources distantes en cas d\'erreur si des miroirs sont disponibles - Mettre en pause - Reprendre - En pause - Tout annuler - Téléchargement uniquement via Wi-Fi - L\'historique de vos téléchargements sera définitivement supprimé - Notifications parfois affichées avec des mangas suggérés - Tous les téléchargements actifs seront annulés, les données partiellement téléchargées seront perdues - Les téléchargements ont été interrompus - Suggestion : %s - Plus - Vous n\'avez pas de téléchargements - Les téléchargements ont repris - Les téléchargements ont été supprimés - Les téléchargements ont été annulés - Voulez-vous recevoir des suggestions de mangas personnalisées \? - WebView non disponible : vérifier si le fournisseur WebView est installé - Traductions - Effacer le cache réseau - Taper - Adresse - Port - Proxy - Téléchargé - Pseudonyme - Proxy d\'optimisation des images - Inverser les couleurs - Utilisez le service wsrv.nl pour réduire le trafic et augmenter la vitesse de chargement des images si possible - %1$s (%2$s) - Mot de passe - Valeur invalide - Autorisation (optionnel) - \ No newline at end of file + Appuyez deux fois sur la touche Retour pour quitter l\'appli + Disponible + Confirmation de sortie + %s - %s + Flux + Importation de mangas + Retiré des favoris + Effacer tout l\'historique + Les 2 dernières heures + Historique effacé + Gérer + Aucun marque-page + Vous pouvez créer un marque-page pendant la lecture d\'un manga + Marque-pages supprimés + Aucune source de mangas + Autoriser les sources de mangas de lire des mangas en ligne + Aléatoire + Réordonner + Vide + Explorer + Vos mangas seront affichés ici + Trouvez ce que vous voulez lire dans la section « Explorer » + Annulé + Le compte existe déjà + Retour + Synchronisation + Synchronisez vos données + Entrez votre courriel pour continuer + Mangas sauvegardés + Cache des pages + Autre cache + Utilisation du stockage + Options + Mode incognito + Aucun chapitre + Défilement automatique + Ch. %1$d/%2$d Pg. %3$d/%4$d + Afficher la barre d\'infos dans le lecteur + Archives des BD + Dossier avec des images + Importation terminée + Vous pouvez supprimer le fichier original du stockage pour gagner de l\'espace + L\'importation va bientôt commencer + Sauvegarde ou abandon des modifications non sauvegardées \? + Abandonner + Rendre les mangas récents disponibles en appuyant longuement sur l\'icône de l\'application + Taper sur le bord droit ou appuyer sur la touche droite permet toujours de passer à la page suivante + Contrôle ergonomique du lecteur + Afficher les raccourcis des mangas récents + Correction des couleurs + Luminosité + Contraste + Réinitialiser + Les paramètres de couleurs choisis seront sauvegardés pour ce manga + Il n\'y a plus d\'espace sur l\'appareil + Afficher le curseur de changement de page + Zoom Webtoon + Activez le Wi-Fi ou le réseau mobile pour lire les mangas en ligne + Différentes langues + Le réseau n\'est pas disponible + Compact + Erreur côté serveur (%1$d). Veuillez réessayer plus tard + Effacer aussi les informations sur les nouveaux chapitres + Source désactivée + Préchargement du contenu + Marquer comme actuel + Partager les journaux + Activer la journalisation + Enregistrer certaines actions à des fins de débogage + Langue + Afficher le contenu suspect + Dynamique + Schéma de couleurs + Afficher en vue grille + Pour suivre la progression de la lecture, sélectionnez Menu → Suivre sur l\'écran des détails du manga. + Prestations de service + Il n\'y a rien ici + Sakura + Rikka + Miku + Asuka + Mion + Mamimi + Autoriser les mises à jour instables + Téléchargement commencé + Kanade + Proposer des mises à jour des versions bêta de l\'application + En-tête UserAgent + Veuillez redémarrer l\'application pour appliquer ces changements + Compris + Vitesse + Importer une sauvegarde des données de l\'utilisateur créée précédemment + Vous pouvez sélectionner un répertoire contenant des archives ou des images. Chaque archive (ou sous-répertoire) sera reconnue comme un chapitre. + Vous pouvez sélectionner un ou plusieurs fichiers .cbz ou .zip, chaque fichier sera reconnu comme un manga séparé. + Afficher sur l\'étagère + Appuyez sur un élément et maintenez-le enfoncé pour le réorganiser + Trouver des similaires + Arrêter le téléchargement lors du passage à un réseau mobile + Vous pouvez vous connecter à un compte existant ou en créer un nouveau + Adresse du serveur + Vous pouvez utiliser un serveur de synchronisation autohébergé ou un serveur par défaut. Ne modifiez pas ce paramètre si vous n\'êtes pas sûr·e de ce que vous faites. + Retrait terminé + Activer + Non merci + Paramètres de synchronisation + Ignorer les erreurs SSL + Choisir le miroir automatiquement + Changement automatique de domaine pour les sources distantes en cas d\'erreur si des miroirs sont disponibles + Mettre en pause + Reprendre + En pause + Tout annuler + Téléchargement uniquement via Wi-Fi + L\'historique de vos téléchargements sera définitivement supprimé + Notifications parfois affichées avec des mangas suggérés + Tous les téléchargements actifs seront annulés, les données partiellement téléchargées seront perdues + Les téléchargements ont été interrompus + Suggestion : %s + Plus + Vous n\'avez pas de téléchargements + Les téléchargements ont repris + Les téléchargements ont été supprimés + Les téléchargements ont été annulés + Voulez-vous recevoir des suggestions de mangas personnalisées \? + WebView non disponible : vérifier si le fournisseur WebView est installé + Traductions + Effacer le cache réseau + Taper + Adresse + Port + Proxy + Téléchargé + Pseudonyme + Proxy d\'optimisation des images + Inverser les couleurs + Utilisez le service wsrv.nl pour réduire le trafic et augmenter la vitesse de chargement des images si possible + %1$s (%2$s) + Mot de passe + Valeur invalide + Autorisation (optionnel) + diff --git a/app/src/main/res/values-hi/plurals.xml b/app/src/main/res/values-hi/plurals.xml index 43fb5c692..ad027e19d 100644 --- a/app/src/main/res/values-hi/plurals.xml +++ b/app/src/main/res/values-hi/plurals.xml @@ -12,10 +12,6 @@ %1$d घंटेभर_पहले %1$d घंटोंभर_पहले - - कुल %1$d पेज - कुल %1$d पेजेस - %1$d नया चैप्टर %1$d नए चैप्टर diff --git a/app/src/main/res/values-in/plurals.xml b/app/src/main/res/values-in/plurals.xml index 3842c1fef..695fda2dd 100644 --- a/app/src/main/res/values-in/plurals.xml +++ b/app/src/main/res/values-in/plurals.xml @@ -1,8 +1,5 @@ - - Total %1$d halaman - %1$d item diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index de4eb06bd..c936966c4 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -1,429 +1,425 @@ - Penyimpanan lokal - Favorit - Riwayat - Terjadi kesalahan - Kesalahan jaringan - Detail - Kisi - Mode daftar - Pengaturan - Sumber jarak jauh - Memuat… - Menghitung… - Bab %1$d dari %2$d - Tutup - Coba lagi - Nihil - Belum ada riwayat - Baca - Belum ada favorit - Favoritkan ini - Kategori baru - Tambah - Simpan - Bagikan - Buat pintasan… - Bagikan %s - Cari - Cari komik - Mengunduh… - Memproses… - Diunduh - Unduhan - Nama - Populer - Diperbarui - Terbaru - Peringkat - Urutan penyortiran - Saring - Tema - Terang - Gelap - Ikuti sistem - Halaman - Bersihkan - Hapus - Bersihkan riwayat - Hapus - Tindakan ini tidak didukung - Pilih antara berkas ZIP atau CBZ. - Tidak ada deskripsi - \"%s\" dihapus dari penyimpanan lokal - Simpan halaman - Disimpan - Bagikan gambar - Impor - Riwayat dan cache - Bersihkan cache halaman - B|kB|MB|GB|TB - Standar - Ukuran kisi - Cari di %s - Hapus komik - Hapus \"%s\" dari perangkat secara permanen\? - Pengaturan pembaca - Ganti halaman - Bab - Daftar - Daftar terperinci - Bersihkan semua riwayat baca secara permanen\? - Webtoon - Mode baca - Tombol volume - Lanjut - Bersihkan cache gambar mini - Bersihkan riwayat pencarian - Dibersihkan - Domain - Versi baru aplikasi tersedia - Buka di peramban web - Simpan - Pemberitahuan - %1$d dari %2$d diaktifkan - Bab baru - Unduh - Pengaturan pemberitahuan - Suara pemberitahuan - Sepi juga di sini… - Apa yang Anda baca akan ditampilkan di sini - Cari apa untuk di baca di bilah samping. - Simpan sesuatu dulu - Rak - Baru-baru ini - Animasi halaman - Folder unduhan - Tidak tersedia - Tidak ada penyimpanan yang tersedia - Penyimpanan lain - Selesai - Semua favorit - Kategori kosong - Baca nanti - Pembaruan - Bab baru dari apa yang Anda baca ditampilkan di sini - Hasil pencarian - Versi baru: %s - Ukuran: %s - Dibersihkan - Pembaruan - Mencari pembaruan - Jangan periksa - Kata sandi salah - Lindungi aplikasi - Ulangi kata sandi - Mode skala - Buat cadangan data - Dipulihkan - Semua data dipulihkan - Data berhasil dipulihkan, tapi ada kesalahan - Anda dapat membuat cadangan riwayat dan favorit Anda dan memulihkannya - Baru saja - Lama - Kelompok - Hari ini - Ketuk untuk coba lagi - Konfigurasi yang dipilih akan diingat untuk komik ini - Diam - CAPTCHA diperlukan - Selesaikan - Bersihkan kuki - Semua kuki telah dihapus - Bersihkan aliran - Periksa bab baru - Masuk untuk melihat konten ini - Selanjutnya - Masukkan kata sandi untuk memulai aplikasi - Konfirmasi - Hapus semua kueri pencarian baru-baru ini secara permanen\? - Selamat Datang - Cadangan disimpan - Beberapa perangkat mempunyai perilaku sistem yang berbeda, yang mungkin akan merusak tugas latar belakang. - Baca lebih lanjut - Bab ini menghilang - Terjemahan - Masuk pada %s tidak didukung - Anda akan keluar dari semua sumber - Genre - Selesai - Sedang berlangsung - Standar - Kecualikan komik NSFW dari riwayat - Nomor halaman - Sumber yang digunakan - Sumber yang tersedia - Kebijakan tangkapan layar - Bolehkan - Blokir pada NSFW - Selalu blokir - Saran - Aktifkan saran - Sarankan manga berdasarkan preferensi Anda - Semua data hanya dianalisis secara lokal pada perangkat ini dan tidak pernah dikirim ke mana pun. - Mulai membaca komik dan Anda akan mendapatkan saran yang dipersonalisasi - Jangan menyarankan komik NSFW - Selalu - Muat ulang halaman - Masuk sebagai %s - Diaktifkan - Dinonaktifkan - Tidak bisa memuat daftar genre - Atur ulang filter - Cari genre - Pilih bahasa komik yang ingin Anda baca. Anda bisa mengubahnya nanti di pengaturan. - Jangan Pernah - Hanya di Wi-Fi - 18+ - Berbagai bahasa - Cari bab - Tidak ada bab di komik ini - %1$s%% - Tampilan - Konten - Kecualikan genre - Tentukan genre yang Anda tidak ingin lihat di saran - Hapus yang dipilih dari perangkat secara permanen\? - Selesai menghapus - Perlambat unduhan - Memperbarui saran - Membantu menghidari pemblokiran alamat IP Anda - Bab akan dihapus di latar belakang - Sembunyikan - Tersedia sumber komik baru - Periksa bab baru dan beri tahu tentang itu - Anda akan menerima pemberitahuan tentang pembaruan komik yang Anda baca - Anda tidak akan menerima pemberitahuan, tapi bab baru akan disorot di daftar - Aktifkan pemberitahuan - Nama - Sunting - Sunting kategori - Tidak ada kategori favorit - Tambah markah - Hapus markah - Markah - Markah dihapus - Markah ditambahkan - Urung - Dihapus dari riwayat - Mode baca - Otomatis deteksi mode pembaca - Secara otomatis mendeteksi jika komik itu webtoon - Kategori baru - Indikator LED - Getaran - Kategori favorit - Hapus - Bersihkan aliran pembaruan - Kanan-ke-kiri - Putar layar - Pembaruan aliran akan dimulai - Masukkan kata sandi - Tanya kata sandi ketika memulai Kotatsu - Tentang - Periksa pembaruan - Kata sandi tidak sama - Versi %s - Penyimpanan internal - Penyimpanan eksternal - Kesalahan - Tidak ada pembaruan yang tersedia - Menggunakan daya lebih sedikit pada layar AMOLED - Hitam - Pencadangan dan pemulihan - Kemarin - Pulihkan dari cadangan - Berkas tidak ditemukan - Kata sandi harus 4 karakter atau lebih - Mempersiapkan… - Bersihkan semua riwayat pembaruan secara permanen\? - Masuk - Standar: %s - Unduh atau baca bab yang hilang ini secara daring. - Terjemahkan aplikasi ini - Tekan di tepi - Komik ini memiliki %s. Simpan semuanya\? - Pas tengah - Pas tinggi - Pas lebar - Balik - Mengantri - Resmi - Simpan dari sumber daring atau berkas impor. - Komik Anda akan ditampilkan di sini - Cari apa untuk dibaca di bagian «Jelajah» - Masukkan surel Anda untuk melanjutkan - Dibaca ulang - Jelajah - Direncanakan - Selesai - Dibatalkan - Sinkronisasi data Anda - Pelacakan - Keluar - Sinkronisasi - Kirim - Dibaca - Ditunda - Domain tidak valid - Belum ada markah - Anda bisa membuat markah ketika membaca komik - Markah dihapus - Tidak ada sumber komik - Acak - Kosong - Tampilkan bilah informasi di pembaca - Mengimpor komik - Dua jam terakhir - Tampilkan semua - Riwayat dihapus - Hapus semua riwayat - Pilihan - Impor selesai - Dihapus dari favorit - Impor akan segera dimulai - Konten tidak ditemukan atau dihapus - Tekan Kembali dua kali untuk keluar dari aplikasi - Konfirmasi keluar - Cache halaman - Cache lainnya - Penggunaan penyimpanan - Tersedia - Mode penyamaran - Gulir otomatis - Arsip komik - Folder dengan gambar - Anda bisa menghapus berkas asli dari penyimpanan untuk menghemat ruang - Umpan - Rincian error:<tt>%1$s</tt><br><br>1. Coba <a href=%2$s>buka manga di peramban web</a> untuk memastikan manga tersebut tersedia di sumbernya</a>2. Pastikan Anda menggunakan <a href= >manga versi terbaru</a><br>3. Jika tersedia, kirimkan laporan kesalahan ke pengembang. Pastikan Anda menggunakan <a href=kotatsu://about>versi terbaru Kotatsu</a><br>3. Jika tersedia, kirimkan laporan kesalahan ke pengembang. - Kecerahan - Kontras - Atur Ulang - Pengaturan warna yang dipilih akan diingat untuk komik ini - Menyimpan atau membuang perubahan yang belum disimpan\? - Buang - Gunakan sidik jari jika tersedia - Komik dari favorit Anda - Komik yang baru-baru ini Anda baca - Penghapusan data - Akun sudah ada - Kembali - Membantu pemeriksaan pembaruan di latar belakang - Ada sesuatu yang salah. Mohon untuk mengirim laporan kutu (bug) ke pengembang untuk membantu kami memperbaikinya. - Lapor - Komik yang ditandai sebagai NSFW tidak akan ditambahkan ke riwayat dan pencapaian Anda tidak akan disimpan - Bisa membantu dalam beberapa masalah. Seluruh otorisasi akan menjadi tidak valid - Kelola - Aktifkan sumber komik untuk membaca komik daring - Yakin ingin menghapus kategori favorit yang dipilih\? + Penyimpanan lokal + Favorit + Riwayat + Terjadi kesalahan + Kesalahan jaringan + Detail + Kisi + Mode daftar + Pengaturan + Sumber jarak jauh + Memuat… + Menghitung… + Bab %1$d dari %2$d + Tutup + Coba lagi + Nihil + Belum ada riwayat + Baca + Belum ada favorit + Favoritkan ini + Kategori baru + Tambah + Simpan + Bagikan + Buat pintasan… + Bagikan %s + Cari + Cari komik + Mengunduh… + Memproses… + Diunduh + Unduhan + Nama + Populer + Diperbarui + Terbaru + Peringkat + Urutan penyortiran + Saring + Tema + Terang + Gelap + Ikuti sistem + Halaman + Bersihkan + Hapus + Bersihkan riwayat + Hapus + Tindakan ini tidak didukung + Pilih antara berkas ZIP atau CBZ. + Tidak ada deskripsi + \"%s\" dihapus dari penyimpanan lokal + Simpan halaman + Disimpan + Bagikan gambar + Impor + Bersihkan cache halaman + B|kB|MB|GB|TB + Standar + Ukuran kisi + Cari di %s + Hapus komik + Hapus \"%s\" dari perangkat secara permanen\? + Pengaturan pembaca + Ganti halaman + Bab + Daftar + Daftar terperinci + Bersihkan semua riwayat baca secara permanen\? + Webtoon + Mode baca + Tombol volume + Lanjut + Bersihkan cache gambar mini + Bersihkan riwayat pencarian + Dibersihkan + Domain + Versi baru aplikasi tersedia + Buka di peramban web + Simpan + Pemberitahuan + %1$d dari %2$d diaktifkan + Bab baru + Unduh + Pengaturan pemberitahuan + Suara pemberitahuan + Sepi juga di sini… + Apa yang Anda baca akan ditampilkan di sini + Cari apa untuk di baca di bilah samping. + Simpan sesuatu dulu + Rak + Baru-baru ini + Animasi halaman + Folder unduhan + Tidak tersedia + Tidak ada penyimpanan yang tersedia + Penyimpanan lain + Selesai + Semua favorit + Kategori kosong + Baca nanti + Pembaruan + Bab baru dari apa yang Anda baca ditampilkan di sini + Hasil pencarian + Versi baru: %s + Ukuran: %s + Dibersihkan + Pembaruan + Mencari pembaruan + Jangan periksa + Kata sandi salah + Lindungi aplikasi + Ulangi kata sandi + Mode skala + Buat cadangan data + Dipulihkan + Semua data dipulihkan + Data berhasil dipulihkan, tapi ada kesalahan + Anda dapat membuat cadangan riwayat dan favorit Anda dan memulihkannya + Baru saja + Lama + Kelompok + Hari ini + Ketuk untuk coba lagi + Konfigurasi yang dipilih akan diingat untuk komik ini + Diam + CAPTCHA diperlukan + Selesaikan + Bersihkan kuki + Semua kuki telah dihapus + Bersihkan aliran + Periksa bab baru + Masuk untuk melihat konten ini + Selanjutnya + Masukkan kata sandi untuk memulai aplikasi + Konfirmasi + Hapus semua kueri pencarian baru-baru ini secara permanen\? + Selamat Datang + Cadangan disimpan + Beberapa perangkat mempunyai perilaku sistem yang berbeda, yang mungkin akan merusak tugas latar belakang. + Baca lebih lanjut + Bab ini menghilang + Terjemahan + Masuk pada %s tidak didukung + Anda akan keluar dari semua sumber + Genre + Selesai + Sedang berlangsung + Standar + Kecualikan komik NSFW dari riwayat + Nomor halaman + Sumber yang digunakan + Sumber yang tersedia + Kebijakan tangkapan layar + Bolehkan + Blokir pada NSFW + Selalu blokir + Saran + Aktifkan saran + Sarankan manga berdasarkan preferensi Anda + Semua data hanya dianalisis secara lokal pada perangkat ini dan tidak pernah dikirim ke mana pun. + Mulai membaca komik dan Anda akan mendapatkan saran yang dipersonalisasi + Jangan menyarankan komik NSFW + Selalu + Muat ulang halaman + Masuk sebagai %s + Diaktifkan + Dinonaktifkan + Tidak bisa memuat daftar genre + Atur ulang filter + Pilih bahasa komik yang ingin Anda baca. Anda bisa mengubahnya nanti di pengaturan. + Jangan Pernah + Hanya di Wi-Fi + 18+ + Berbagai bahasa + Cari bab + Tidak ada bab di komik ini + %1$s%% + Tampilan + Kecualikan genre + Tentukan genre yang Anda tidak ingin lihat di saran + Hapus yang dipilih dari perangkat secara permanen\? + Selesai menghapus + Perlambat unduhan + Memperbarui saran + Membantu menghidari pemblokiran alamat IP Anda + Bab akan dihapus di latar belakang + Sembunyikan + Tersedia sumber komik baru + Periksa bab baru dan beri tahu tentang itu + Anda akan menerima pemberitahuan tentang pembaruan komik yang Anda baca + Anda tidak akan menerima pemberitahuan, tapi bab baru akan disorot di daftar + Aktifkan pemberitahuan + Nama + Sunting + Sunting kategori + Tidak ada kategori favorit + Tambah markah + Hapus markah + Markah + Markah dihapus + Markah ditambahkan + Urung + Dihapus dari riwayat + Mode baca + Otomatis deteksi mode pembaca + Secara otomatis mendeteksi jika komik itu webtoon + Kategori baru + Indikator LED + Getaran + Kategori favorit + Hapus + Bersihkan aliran pembaruan + Kanan-ke-kiri + Putar layar + Pembaruan aliran akan dimulai + Masukkan kata sandi + Tanya kata sandi ketika memulai Kotatsu + Tentang + Periksa pembaruan + Kata sandi tidak sama + Versi %s + Penyimpanan internal + Penyimpanan eksternal + Kesalahan + Tidak ada pembaruan yang tersedia + Menggunakan daya lebih sedikit pada layar AMOLED + Hitam + Pencadangan dan pemulihan + Kemarin + Pulihkan dari cadangan + Berkas tidak ditemukan + Kata sandi harus 4 karakter atau lebih + Mempersiapkan… + Bersihkan semua riwayat pembaruan secara permanen\? + Masuk + Standar: %s + Terjemahkan aplikasi ini + Tekan di tepi + Komik ini memiliki %s. Simpan semuanya\? + Pas tengah + Pas tinggi + Pas lebar + Balik + Mengantri + Resmi + Simpan dari sumber daring atau berkas impor. + Komik Anda akan ditampilkan di sini + Cari apa untuk dibaca di bagian «Jelajah» + Masukkan surel Anda untuk melanjutkan + Dibaca ulang + Jelajah + Direncanakan + Selesai + Dibatalkan + Sinkronisasi data Anda + Pelacakan + Keluar + Sinkronisasi + Kirim + Dibaca + Ditunda + Domain tidak valid + Belum ada markah + Anda bisa membuat markah ketika membaca komik + Markah dihapus + Tidak ada sumber komik + Acak + Kosong + Tampilkan bilah informasi di pembaca + Mengimpor komik + Dua jam terakhir + Tampilkan semua + Riwayat dihapus + Hapus semua riwayat + Pilihan + Impor selesai + Dihapus dari favorit + Impor akan segera dimulai + Konten tidak ditemukan atau dihapus + Tekan Kembali dua kali untuk keluar dari aplikasi + Konfirmasi keluar + Cache halaman + Cache lainnya + Penggunaan penyimpanan + Tersedia + Mode penyamaran + Gulir otomatis + Arsip komik + Folder dengan gambar + Anda bisa menghapus berkas asli dari penyimpanan untuk menghemat ruang + Umpan + Rincian error:<tt>%1$s</tt><br><br>1. Coba <a href=%2$s>buka manga di peramban web</a> untuk memastikan manga tersebut tersedia di sumbernya</a>2. Pastikan Anda menggunakan <a href= >manga versi terbaru</a><br>3. Jika tersedia, kirimkan laporan kesalahan ke pengembang. Pastikan Anda menggunakan <a href=kotatsu://about>versi terbaru Kotatsu</a><br>3. Jika tersedia, kirimkan laporan kesalahan ke pengembang. + Kecerahan + Kontras + Atur Ulang + Pengaturan warna yang dipilih akan diingat untuk komik ini + Menyimpan atau membuang perubahan yang belum disimpan\? + Buang + Gunakan sidik jari jika tersedia + Komik dari favorit Anda + Komik yang baru-baru ini Anda baca + Penghapusan data + Akun sudah ada + Kembali + Membantu pemeriksaan pembaruan di latar belakang + Ada sesuatu yang salah. Mohon untuk mengirim laporan kutu (bug) ke pengembang untuk membantu kami memperbaikinya. + Lapor + Komik yang ditandai sebagai NSFW tidak akan ditambahkan ke riwayat dan pencapaian Anda tidak akan disimpan + Bisa membantu dalam beberapa masalah. Seluruh otorisasi akan menjadi tidak valid + Kelola + Aktifkan sumber komik untuk membaca komik daring + Yakin ingin menghapus kategori favorit yang dipilih\? \nSemua komik di dalamnya akan hilang dan ini tidak dapat dibatalkan. - Atur Ulang - Komik tersimpan - Tekan Kembali lagi untuk keluar - Tidak ada bab - Tampilkan pintasan komik baru-baru ini - Buat komik baru-baru ini tersedia dengan menekan panjang pada ikon aplikasi - Pilih jangkauan - Matikan semua - Hanya gestur - DNS over HTTPS - Istirahat - Mamimi - Kesalahan sisi server (%1$d). Silakan coba lagi nanti - kompak - Pramuat konten - %s - %s - Tidak ada apapun di sini - Ketuk di tepi kanan atau menekan tombol kanan akan selalu beralih ke halaman berikutnya - Sumber dinonaktifkan - Tandai sebagai saat ini - Tampilkan konten yang mencurigakan - Untuk melacak kemajuan membaca, pilih Menu → Lacak di layar detail komik. - Layanan - Juga informasi yang jelas tentang bab baru - Nyalakan Wi-Fi atau jaringan seluler untuk membaca komik daring - Tajuk Agen Pengguna - Mulai ulang aplikasi untuk menerapkan perubahan ini - Kanade - Bagikan log - Tidak ada ruang tersisa di perangkat - Izinkan pembaruan yang tidak stabil - Usulkan pembaruan ke versi beta - Unduh dimulai - Tampilkan indikator kemajuan membaca - Tampilkan persentase baca dalam riwayat dan favorit - Bahasa - Cobalah untuk memformulasi ulang kueri. - Tetap di awal - Bab. %1$d/%2$d Hal. %3$d/%4$d - Aktifkan pencatatan - Rekam beberapa tindakan untuk tujuan debug - Dinamis - Skema warna - Perlihatkan dalam tampilan kisi - Miku - Asuka - Mion - Rikka - Sakura - Pemrosesan komik tersimpan - Nonaktifkan pengoptimalan baterai - Kontrol pembaca ergonomis - Koreksi warna - Perlihatkan penggeser peralihan halaman - Zoom webtoon - Berbagai bahasa - Jaringan tidak tersedia - Oke - Ketuk dan tahan item untuk menyusun ulang - Anda dapat memilih satu atau beberapa file .cbz atau .zip, setiap file akan dikenali sebagai komik terpisah. - Anda dapat memilih direktori yang berisi arsip atau gambar. Setiap arsip (atau subdirektori) akan dikenali sebagai sebuah bab. - Kecepatan - Impor cadangan data pengguna yang telah dibuat sebelumnya - Tampilkan di Rak - Anda dapat masuk ke akun yang sudah ada atau membuat akun baru - Temukan serupa - Alamat server - Unduh hanya melalui Wi-Fi - Unduhan telah dibatalkan - Aktifkan - Tidak, terima kasih - Pengaturan sinkronisasi - Anda dapat menggunakan server sinkronisasi yang dihosting sendiri atau server default. Jangan ubah ini jika Anda tidak yakin dengan apa yang Anda lakukan. - Abaikan kesalahan SSL - Pilih cermin secara otomatis - Secara otomatis mengalihkan domain untuk sumber jarak jauh saat terjadi kesalahan jika mirror tersedia - Jeda - Lanjut - Dijeda - Hapus selesai - Batalkan semua - Berhenti mengunduh saat beralih ke jaringan seluler - Saran: %s - Terkadang menampilkan notifikasi dengan manga yang disarankan - Lebih - Semua pengunduhan yang aktif akan dibatalkan, data yang sudah terunduh sebagian akan hilang - Riwayat unduhan Anda akan dihapus secara permanen - Anda tidak memiliki unduhan apa pun - Unduhan telah dilanjutkan - Unduhan telah dijeda - Unduhan telah dihapus - Apakah Anda ingin menerima saran manga yang dipersonalisasi\? - Terjemahan - WebView tidak tersedia: periksa apakah penyedia WebView telah diinstal - Hapus cache jaringan - Tipe - Alamat - Port - Proksi - Nilai tidak valid - %1$s (%2$s) - Gunakan layanan wsrv.nl untuk mengurangi penggunaan lalu lintas dan mempercepat pemuatan gambar jika memungkinkan - Proksi pengoptimalan gambar - NamaUser - Diunduh - Balikkan warna - Kata sandi - Otorisasi (opsional) - \ No newline at end of file + Atur Ulang + Komik tersimpan + Tekan Kembali lagi untuk keluar + Tidak ada bab + Tampilkan pintasan komik baru-baru ini + Buat komik baru-baru ini tersedia dengan menekan panjang pada ikon aplikasi + Pilih jangkauan + Matikan semua + Hanya gestur + DNS over HTTPS + Istirahat + Mamimi + Kesalahan sisi server (%1$d). Silakan coba lagi nanti + kompak + Pramuat konten + %s - %s + Tidak ada apapun di sini + Ketuk di tepi kanan atau menekan tombol kanan akan selalu beralih ke halaman berikutnya + Sumber dinonaktifkan + Tandai sebagai saat ini + Tampilkan konten yang mencurigakan + Untuk melacak kemajuan membaca, pilih Menu → Lacak di layar detail komik. + Layanan + Juga informasi yang jelas tentang bab baru + Nyalakan Wi-Fi atau jaringan seluler untuk membaca komik daring + Tajuk Agen Pengguna + Mulai ulang aplikasi untuk menerapkan perubahan ini + Kanade + Bagikan log + Tidak ada ruang tersisa di perangkat + Izinkan pembaruan yang tidak stabil + Usulkan pembaruan ke versi beta + Unduh dimulai + Tampilkan indikator kemajuan membaca + Tampilkan persentase baca dalam riwayat dan favorit + Bahasa + Cobalah untuk memformulasi ulang kueri. + Tetap di awal + Bab. %1$d/%2$d Hal. %3$d/%4$d + Aktifkan pencatatan + Rekam beberapa tindakan untuk tujuan debug + Dinamis + Skema warna + Perlihatkan dalam tampilan kisi + Miku + Asuka + Mion + Rikka + Sakura + Pemrosesan komik tersimpan + Nonaktifkan pengoptimalan baterai + Kontrol pembaca ergonomis + Koreksi warna + Perlihatkan penggeser peralihan halaman + Zoom webtoon + Berbagai bahasa + Jaringan tidak tersedia + Oke + Ketuk dan tahan item untuk menyusun ulang + Anda dapat memilih satu atau beberapa file .cbz atau .zip, setiap file akan dikenali sebagai komik terpisah. + Anda dapat memilih direktori yang berisi arsip atau gambar. Setiap arsip (atau subdirektori) akan dikenali sebagai sebuah bab. + Kecepatan + Impor cadangan data pengguna yang telah dibuat sebelumnya + Tampilkan di Rak + Anda dapat masuk ke akun yang sudah ada atau membuat akun baru + Temukan serupa + Alamat server + Unduh hanya melalui Wi-Fi + Unduhan telah dibatalkan + Aktifkan + Tidak, terima kasih + Pengaturan sinkronisasi + Anda dapat menggunakan server sinkronisasi yang dihosting sendiri atau server default. Jangan ubah ini jika Anda tidak yakin dengan apa yang Anda lakukan. + Abaikan kesalahan SSL + Pilih cermin secara otomatis + Secara otomatis mengalihkan domain untuk sumber jarak jauh saat terjadi kesalahan jika mirror tersedia + Jeda + Lanjut + Dijeda + Hapus selesai + Batalkan semua + Berhenti mengunduh saat beralih ke jaringan seluler + Saran: %s + Terkadang menampilkan notifikasi dengan manga yang disarankan + Lebih + Semua pengunduhan yang aktif akan dibatalkan, data yang sudah terunduh sebagian akan hilang + Riwayat unduhan Anda akan dihapus secara permanen + Anda tidak memiliki unduhan apa pun + Unduhan telah dilanjutkan + Unduhan telah dijeda + Unduhan telah dihapus + Apakah Anda ingin menerima saran manga yang dipersonalisasi\? + Terjemahan + WebView tidak tersedia: periksa apakah penyedia WebView telah diinstal + Hapus cache jaringan + Tipe + Alamat + Port + Proksi + Nilai tidak valid + %1$s (%2$s) + Gunakan layanan wsrv.nl untuk mengurangi penggunaan lalu lintas dan mempercepat pemuatan gambar jika memungkinkan + Proksi pengoptimalan gambar + NamaUser + Diunduh + Balikkan warna + Kata sandi + Otorisasi (opsional) + diff --git a/app/src/main/res/values-it/plurals.xml b/app/src/main/res/values-it/plurals.xml index de8c2c03b..0fdb0355c 100644 --- a/app/src/main/res/values-it/plurals.xml +++ b/app/src/main/res/values-it/plurals.xml @@ -1,9 +1,5 @@ - - %1$d pagina in totale - %1$d pagine in totale - %1$d nuovo capitolo %1$d nuovi capitoli diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 193367044..b34a26a79 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,6 +1,5 @@ - Cronologia e cache Nessuna descrizione File non valido. Sono supportati solo ZIP e CBZ. Questa operazione non è supportata @@ -182,7 +181,6 @@ Adatta alla larghezza Modalità scala Capitolo mancante - Questo capitolo manca sul tuo dispositivo. Scaricalo o leggilo in linea. In coda Traduzione Traduci questa applicazione @@ -211,7 +209,6 @@ Abilitato Disabilitato Non suggerire manga NSFW - Trova il genere Ripristina il filtro Seleziona le lingue in cui vuoi leggere i manga. Puoi cambiarla in seguito nelle impostazioni. Mai @@ -225,7 +222,6 @@ Nessun capitolo in questo manga %1$s%% Aspetto - Contenuto Aggiornamento dei suggerimenti Specifica i generi che non vuoi vedere nei suggerimenti Escludi generi diff --git a/app/src/main/res/values-ja/plurals.xml b/app/src/main/res/values-ja/plurals.xml index 5872418c3..cf5756968 100644 --- a/app/src/main/res/values-ja/plurals.xml +++ b/app/src/main/res/values-ja/plurals.xml @@ -15,9 +15,6 @@ %1$dチャプター - - 合計%1$dページ - %1$d新しい章 diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 160cd572a..4f2a2cef9 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1,429 +1,425 @@ - 履歴 - ロード中… - チャプター %1$d of %2$d - 共有 - 履歴を削除 - 検索 - 漫画を検索 - 閉じる - お気に入り - エラーが発生しました - 詳細 - - リスト - 詳細リスト - グリッド - リストモード - マンガのソース - 再試行 - 何も見つかりませんでした - まだ履歴はありません - 読む - お気に入りの本はありません - お気に入りの本 - 新たなカテゴリー - 追加 - 保存 - ショートカットを作成します… - 共有する%s - ダウンロード中… - 処理中… - ダウンロードした本 - ダウンロード - 名前 - 人気 - ローカルストレージ - 最新 - 評価 - ソート順に並べ替え - フォローシステム - クリア - すべての履歴を永久にクリアしますか? - 削除 - 「%s 」がローカルストレージから削除されました - ページを保存 - 保存しました - 画像を共有する - インポート - 消去 - この操作はサポートされていません - 説明がありません - 履歴とキャッシュ - ページのキャッシュをクリアする - B|kB|MB|GB|TB - 設定 - ライトテーマ - フィルター - ダークテーマ - ページ - テーマ - ネットワークエラー - アップデート - ZIPファイルまたはCBZファイルを選択してください。 - 標準 - ウェブトゥーン - 読み取りモード - グリッドのサイズ - %sで検索 - 漫画を削除 - お使いのデバイスから「%s」を完全に削除しますか? - リーダーの設定 - ページを変更 - エッジタップ - ボリュームボタン - 続ける - エラー - サムネイルキャッシュをクリア - クリア - ジェスチャーのみ - 内部ストレージ - ドメイン - ブラウザーで開く - この漫画には%sがあります。 すべて保存しますか? - 保存 - 通知 - %2$dの%1$d - 新しいチャプター - ダウンロード - 通知の設定 - 通知音 - LEDインジケータ - バイブレーション - お気に入りのカテゴリー - 削除 - クエリを再定式化してみてください。 - 読んだ内容がここに表示されます - サイドメニューで何を読むかを見つけてください。 - 最初に何かを保存する - 本棚 - 最近 - ページアニメーション - ダウンロード用のフォルダ - 利用出来ません - 使用可能なストレージがありません - その他のストレージ - 完了 - 全てのお気に入り - 後で読む - 更新 - あなたが読んでいるものの新しいチャプターがここに示されています - の検索結果 - サイズ:%s - 更新フィードをクリア - クリア - アップデート - フィードの更新はまもなく開始されます - アップデートを確認 - チェックしない - Kotatsuを起動したときにパスワードを入力する - パスワードを繰り返す - パスワードが違います - この本の詳細 - 現在のバージョン%s - 検索履歴をクリア - 外部ストレージ - Kotatsuの新しい更新が利用可能です - ここは空っぽです… - 空のカテゴリー - オンラインソースから保存するかファイルをインポートします。 - 新しいバージョン:%s - 画面を回転させる - パスワードを入力してください - パスワードが間違っています - アプリを保護する - 最新のアップデートを確認する - 利用可能なアップデートはありません - 右から左 - 承認済み - %sへのログインはサポートされていません - 完成 - 進行中 - デフォルト - ナンバリングページ - 使用したソース - 利用可能なソース - 新しいカテゴリー - 高さを合わせる - チャプターがありません - すべての更新履歴を完全に消去しますか? - この不足した章をダウンロードしたり、オンラインで読んだりすることができます。 - このコンテンツを表示するにはサインインしてください - ファイルが見つかりません - パスワードは4文字以上である必要があります - ちょうど今 - ずっと前 - バックアップを保存 - グループ - フィードをクリア - バックアップから復元 - 確認 - 履歴とお気に入りのバックアップを作成して復元できます - 続きを読む - ブラック - データは復元されましたがエラーが発生しました - 最近の検索クエリを全て完全に削除しますか? - 幅を合わせる - 新しいチャプターを探しています - アプリを起動するためのパスワードを入力してください - データバックアップを作成 - 解決しました - タップして再試行してください - CAPTCHAが必要です - デフォルト:%s - 昨日 - このアプリを翻訳 - 全てのデータが復元されました - 復元 - 準備中… - 開始時に維持 - バックアップと復元 - リバース - 選択した構成はこの漫画のために記憶されます - クッキーを削除 - フィットセンター - 全てのソースからログアウトされます - NSFW漫画を履歴から除外する - キュー - 全てのCookieが削除されました - 一部のデバイスはシステムでの動作が異なり、バックグラウンドタスクが中断される可能性があります。 - ジャンル - スケールモード - 今日 - Kotatsuを翻訳する(Weblateのサイトに移動します) - 次のページ - サイレント - サインイン - ようこそ - AMOLEDスクリーンでさらに少ない電力を使用 - コンピューティング… - 許可する - 常にブロック - スクリーンショットポリシー - NSFWでブロック - 提案 - すべてのデータは、このデバイス上でローカルでのみ分析され、どこにも送信されることはありません。 - サジェスト機能を有効 - あなたの好みに合わせて漫画を提案 - ジャンルリストを読み込めません - 無効 - マンガを読み始めると、個人的な提案を受けることができます - 有効 - NSFWのマンガを提案しない - フィルターをリセット - ジャンルを探す - Wi-Fiのみ使用 - 決して - 漫画を読みたい言語を選択します。後で設定から変更することができます。 - 常に - ページのプリロード - %sとしてログイン - 18歳以上 - さまざまな言語 - チャプターを検索 - この漫画の章はありません - %1$s%% - コンテンツ - 更新のご提案 - 外観 - ジャンルを除く - サジェストで表示したくないジャンルを指定 - 選択した項目をデバイスから完全に削除しますか? - 削除が完了しました - IPアドレスのブロックを回避することができます - 保存されたマンガの処理 - ダウンロードの速度低下 - チャプターはバックグラウンドで削除されます - 隠す - 新しいマンガソースが利用可能です - 新着チャプターの確認とお知らせ - 読んでいるマンガの更新情報をお知らせします - 通知を有効にする - 通知はありませんが、新しいチャプターはリストでハイライト表示されます - 名称 - 編集 - カテゴリーを編集する - お気に入りのカテゴリーはありません - ブックマーク - ブックマーク削除 - 元に戻す - 履歴から削除 - ブックマークの追加 - ブックマークの削除 - ブックマークを追加 - HTTPS 経由の DNS - リーダーモードの自動検出 - デフォルトモード - マンガがウェブトゥーンかどうかを自動判定 - バッテリー最適化の無効化 - バックグラウンドの更新チェックを支援 - 何か問題が発生しました。開発者にバグレポートを提出し、解決にご協力ください。 - 送信 - すべて無効にする - 最近読んだ漫画 - 指紋がある場合は、指紋を使用する - お気に入りの漫画 - 報告 - 読書 - 再読込 - 完了 - 保留中 - 追跡 - ログアウト - 予定 - ドロップ - データの削除 - 履歴とお気に入りに既読率を表示する - いくつかの問題の場合に助けることができる。すべての認証が無効になります - 読書の進行状況インジケーターを表示 - NSFWとマークされたマンガは履歴に追加されず、進行状況も保存されない - すべて表示 - 無効なドメイン - 範囲を選択 - コンテンツが見つからない、または削除された - 管理 - ランダム - 選択したお気に入りカテゴリを本当に削除してもよいですか? + 履歴 + ロード中… + チャプター %1$d of %2$d + 共有 + 履歴を削除 + 検索 + 漫画を検索 + 閉じる + お気に入り + エラーが発生しました + 詳細 + + リスト + 詳細リスト + グリッド + リストモード + マンガのソース + 再試行 + 何も見つかりませんでした + まだ履歴はありません + 読む + お気に入りの本はありません + お気に入りの本 + 新たなカテゴリー + 追加 + 保存 + ショートカットを作成します… + 共有する%s + ダウンロード中… + 処理中… + ダウンロードした本 + ダウンロード + 名前 + 人気 + ローカルストレージ + 最新 + 評価 + ソート順に並べ替え + フォローシステム + クリア + すべての履歴を永久にクリアしますか? + 削除 + 「%s 」がローカルストレージから削除されました + ページを保存 + 保存しました + 画像を共有する + インポート + 消去 + この操作はサポートされていません + 説明がありません + ページのキャッシュをクリアする + B|kB|MB|GB|TB + 設定 + ライトテーマ + フィルター + ダークテーマ + ページ + テーマ + ネットワークエラー + アップデート + ZIPファイルまたはCBZファイルを選択してください。 + 標準 + ウェブトゥーン + 読み取りモード + グリッドのサイズ + %sで検索 + 漫画を削除 + お使いのデバイスから「%s」を完全に削除しますか? + リーダーの設定 + ページを変更 + エッジタップ + ボリュームボタン + 続ける + エラー + サムネイルキャッシュをクリア + クリア + ジェスチャーのみ + 内部ストレージ + ドメイン + ブラウザーで開く + この漫画には%sがあります。 すべて保存しますか? + 保存 + 通知 + %2$dの%1$d + 新しいチャプター + ダウンロード + 通知の設定 + 通知音 + LEDインジケータ + バイブレーション + お気に入りのカテゴリー + 削除 + クエリを再定式化してみてください。 + 読んだ内容がここに表示されます + サイドメニューで何を読むかを見つけてください。 + 最初に何かを保存する + 本棚 + 最近 + ページアニメーション + ダウンロード用のフォルダ + 利用出来ません + 使用可能なストレージがありません + その他のストレージ + 完了 + 全てのお気に入り + 後で読む + 更新 + あなたが読んでいるものの新しいチャプターがここに示されています + の検索結果 + サイズ:%s + 更新フィードをクリア + クリア + アップデート + フィードの更新はまもなく開始されます + アップデートを確認 + チェックしない + Kotatsuを起動したときにパスワードを入力する + パスワードを繰り返す + パスワードが違います + この本の詳細 + 現在のバージョン%s + 検索履歴をクリア + 外部ストレージ + Kotatsuの新しい更新が利用可能です + ここは空っぽです… + 空のカテゴリー + オンラインソースから保存するかファイルをインポートします。 + 新しいバージョン:%s + 画面を回転させる + パスワードを入力してください + パスワードが間違っています + アプリを保護する + 最新のアップデートを確認する + 利用可能なアップデートはありません + 右から左 + 承認済み + %sへのログインはサポートされていません + 完成 + 進行中 + デフォルト + ナンバリングページ + 使用したソース + 利用可能なソース + 新しいカテゴリー + 高さを合わせる + チャプターがありません + すべての更新履歴を完全に消去しますか? + このコンテンツを表示するにはサインインしてください + ファイルが見つかりません + パスワードは4文字以上である必要があります + ちょうど今 + ずっと前 + バックアップを保存 + グループ + フィードをクリア + バックアップから復元 + 確認 + 履歴とお気に入りのバックアップを作成して復元できます + 続きを読む + ブラック + データは復元されましたがエラーが発生しました + 最近の検索クエリを全て完全に削除しますか? + 幅を合わせる + 新しいチャプターを探しています + アプリを起動するためのパスワードを入力してください + データバックアップを作成 + 解決しました + タップして再試行してください + CAPTCHAが必要です + デフォルト:%s + 昨日 + このアプリを翻訳 + 全てのデータが復元されました + 復元 + 準備中… + 開始時に維持 + バックアップと復元 + リバース + 選択した構成はこの漫画のために記憶されます + クッキーを削除 + フィットセンター + 全てのソースからログアウトされます + NSFW漫画を履歴から除外する + キュー + 全てのCookieが削除されました + 一部のデバイスはシステムでの動作が異なり、バックグラウンドタスクが中断される可能性があります。 + ジャンル + スケールモード + 今日 + Kotatsuを翻訳する(Weblateのサイトに移動します) + 次のページ + サイレント + サインイン + ようこそ + AMOLEDスクリーンでさらに少ない電力を使用 + コンピューティング… + 許可する + 常にブロック + スクリーンショットポリシー + NSFWでブロック + 提案 + すべてのデータは、このデバイス上でローカルでのみ分析され、どこにも送信されることはありません。 + サジェスト機能を有効 + あなたの好みに合わせて漫画を提案 + ジャンルリストを読み込めません + 無効 + マンガを読み始めると、個人的な提案を受けることができます + 有効 + NSFWのマンガを提案しない + フィルターをリセット + Wi-Fiのみ使用 + 決して + 漫画を読みたい言語を選択します。後で設定から変更することができます。 + 常に + ページのプリロード + %sとしてログイン + 18歳以上 + さまざまな言語 + チャプターを検索 + この漫画の章はありません + %1$s%% + 更新のご提案 + 外観 + ジャンルを除く + サジェストで表示したくないジャンルを指定 + 選択した項目をデバイスから完全に削除しますか? + 削除が完了しました + IPアドレスのブロックを回避することができます + 保存されたマンガの処理 + ダウンロードの速度低下 + チャプターはバックグラウンドで削除されます + 隠す + 新しいマンガソースが利用可能です + 新着チャプターの確認とお知らせ + 読んでいるマンガの更新情報をお知らせします + 通知を有効にする + 通知はありませんが、新しいチャプターはリストでハイライト表示されます + 名称 + 編集 + カテゴリーを編集する + お気に入りのカテゴリーはありません + ブックマーク + ブックマーク削除 + 元に戻す + 履歴から削除 + ブックマークの追加 + ブックマークの削除 + ブックマークを追加 + HTTPS 経由の DNS + リーダーモードの自動検出 + デフォルトモード + マンガがウェブトゥーンかどうかを自動判定 + バッテリー最適化の無効化 + バックグラウンドの更新チェックを支援 + 何か問題が発生しました。開発者にバグレポートを提出し、解決にご協力ください。 + 送信 + すべて無効にする + 最近読んだ漫画 + 指紋がある場合は、指紋を使用する + お気に入りの漫画 + 報告 + 読書 + 再読込 + 完了 + 保留中 + 追跡 + ログアウト + 予定 + ドロップ + データの削除 + 履歴とお気に入りに既読率を表示する + いくつかの問題の場合に助けることができる。すべての認証が無効になります + 読書の進行状況インジケーターを表示 + NSFWとマークされたマンガは履歴に追加されず、進行状況も保存されない + すべて表示 + 無効なドメイン + 範囲を選択 + コンテンツが見つからない、または削除された + 管理 + ランダム + 選択したお気に入りカテゴリを本当に削除してもよいですか? \nその中にあるマンガはすべて失われ、元に戻すことはできません。 - - 探検 - アプリを終了するには、戻るを2回押してください - 保存したマンガ - チャプターなし - 自動スクロール - マンガのインポート - 続行するにはメールアドレスを入力してください - «探索»セクションで読むべきものを見つける - インポートが完了しました - あなたのマンガはここに表示されます - キャンセル - データの同期 - アカウントは既に存在します - 戻る - 過去 2 時間 - ブックマークはまだありません - 同期 - ページキャッシュ - 利用可能 - すべての履歴を消去する - 履歴が消去されました - 並べ替え - マンガを読みながらブックマークを作成することができます - ブックマークを削除しました - マンガのソースがない - マンガのソースを有効にして、オンラインでマンガを読めるようにする - もう一度戻るを押して終了します - %s -%s - 退出確認 - ストレージの使用状況 - その他のキャッシュ - シークレットモード - 画像を含むフォルダ - まもなくインポートが開始されます - お気に入りから削除 - オプション - ストレージから元のファイルを削除して、容量を節約することができます - Ch.%1$d/%2$d Pg.%3$d/%4$d - リーダーで情報バーを表示する - コミックアーカイブ - フィード - エラーの詳細:<br><tt>%1$s</tt><br><br>1. <a href=%2$s>Webブラウザで漫画を開いてみて</a>、そのソースで利用可能かどうか確認してください<br>2.<a href=kotatsu://about>最新版のこたつ</a><br>3.利用可能であれば、開発者にエラーレポートを送ってみてください。 - 人間工学に基づいたリーダーコントロール - 最近のマンガのショートカットを表示 - アプリケーションアイコンを長押しして最近のマンガを利用できるようにする - 右端をタップするか、右キーを押すと、常に次のページに切り替わります - 色補正 - 輝度 - コントラスト - リセット - 未保存の変更を保存または破棄しますか\? - 選択した色の設定は、この漫画のために記憶されます - 破棄 - デバイスに空き容量がありません - ページ切り替えスライダーを表示 - サーバーサイドエラー (%1$d) です。後で再試行してください - 新しいチャプターの情報も明確に - さまざまな言語 - ネットワークが利用できません - Wi-Fiまたはモバイルネットワークをオンにして、オンラインでマンガを読むことができます - Webtoonズーム - コンパクト - マミミ - - ここには何もありません - 読書の進捗状況を確認するには、マンガの詳細画面で「メニュー」→「追跡」を選択します。 - サービス - デバッグ目的でいくつかのアクションを記録する - ミク - ユーザー エージェント ヘッダー - コンテンツのプリロード - ログを共有 - 不安定な更新を許可 - アプリのベータ版へのアップデートを提案する - ダウンロードが開始されました - 言語 - ソースが無効になっています - 現在としてマーク - ログ記録を有効にする - 疑わしいコンテンツを表示する - ダイナミック - 配色 - グリッドビューで表示 - アスカ - ミオン - リッカ - さくら - この変更を適用するには、アプリケーションを再起動してください - 項目をタップ&ホールドして並び替えをすることができます - .cbzまたは.zipファイルを1つ以上選択することができ、各ファイルは別のマンガとして認識されます。 - 了解 - 翻訳 - 過去に作成したユーザーデータのバックアップをインポートする - 棚に表示 - %1$s (%2$s) - 色を反転させる - 有効 - 結構です - ネットワークキャッシュをクリアする - ダウンロードは削除されました - 自分で用意した同期サーバーか、デフォルトのものを使用することができます。よく分からない場合は変更しないでください。 - 一時停止 - ダウンロードがキャンセルされました - WebViewが利用できません:WebView providerがインストールされているかどうかを確認してください - ダウンロード済み - 画像最適化プロキシ - wsrv.nl サービスを使用して、トラフィック使用量を削減し、可能であれば画像の読み込みを高速化します - アーカイブや画像のあるディレクトリを選択することができます。各アーカイブ(またはサブディレクトリ)は、1つのチャプターとして認識されます。 - 類似したものを探す - タイプ - アドレス - ポート - プロキシ - 同期の設定 - サーバーアドレス - 速度 - SSLエラーを無視する - ミラーを自動的に選択する - ミラーがある場合、エラー時にリモートソースのドメインを自動で切り替える - 履歴書 - 一時停止 - 全てキャンセル - Wi-Fi経由でのみダウンロード - モバイルデータ通信への切り替え時にダウンロードを停止する - 提案: %s - 提案されたマンガの通知を表示することがあります - もっと見る - アクティブなダウンロードはすべてキャンセルされ、部分的にダウンロードされたデータは失われます - ダウンロード履歴は完全に削除されます - ダウンロードはありません - ダウンロードが再開されました - ダウンロードが一時停止されました - パーソナライズされた漫画の提案を受け取りますか? - 削除が完了 - 既存のアカウントにサインインするか、新規にアカウントを作成することができます - 無効な値 - ユーザー名 - パスワード - オーソライズ(オプション) - \ No newline at end of file + + 探検 + アプリを終了するには、戻るを2回押してください + 保存したマンガ + チャプターなし + 自動スクロール + マンガのインポート + 続行するにはメールアドレスを入力してください + «探索»セクションで読むべきものを見つける + インポートが完了しました + あなたのマンガはここに表示されます + キャンセル + データの同期 + アカウントは既に存在します + 戻る + 過去 2 時間 + ブックマークはまだありません + 同期 + ページキャッシュ + 利用可能 + すべての履歴を消去する + 履歴が消去されました + 並べ替え + マンガを読みながらブックマークを作成することができます + ブックマークを削除しました + マンガのソースがない + マンガのソースを有効にして、オンラインでマンガを読めるようにする + もう一度戻るを押して終了します + %s -%s + 退出確認 + ストレージの使用状況 + その他のキャッシュ + シークレットモード + 画像を含むフォルダ + まもなくインポートが開始されます + お気に入りから削除 + オプション + ストレージから元のファイルを削除して、容量を節約することができます + Ch.%1$d/%2$d Pg.%3$d/%4$d + リーダーで情報バーを表示する + コミックアーカイブ + フィード + エラーの詳細:<br><tt>%1$s</tt><br><br>1. <a href=%2$s>Webブラウザで漫画を開いてみて</a>、そのソースで利用可能かどうか確認してください<br>2.<a href=kotatsu://about>最新版のこたつ</a><br>3.利用可能であれば、開発者にエラーレポートを送ってみてください。 + 人間工学に基づいたリーダーコントロール + 最近のマンガのショートカットを表示 + アプリケーションアイコンを長押しして最近のマンガを利用できるようにする + 右端をタップするか、右キーを押すと、常に次のページに切り替わります + 色補正 + 輝度 + コントラスト + リセット + 未保存の変更を保存または破棄しますか\? + 選択した色の設定は、この漫画のために記憶されます + 破棄 + デバイスに空き容量がありません + ページ切り替えスライダーを表示 + サーバーサイドエラー (%1$d) です。後で再試行してください + 新しいチャプターの情報も明確に + さまざまな言語 + ネットワークが利用できません + Wi-Fiまたはモバイルネットワークをオンにして、オンラインでマンガを読むことができます + Webtoonズーム + コンパクト + マミミ + + ここには何もありません + 読書の進捗状況を確認するには、マンガの詳細画面で「メニュー」→「追跡」を選択します。 + サービス + デバッグ目的でいくつかのアクションを記録する + ミク + ユーザー エージェント ヘッダー + コンテンツのプリロード + ログを共有 + 不安定な更新を許可 + アプリのベータ版へのアップデートを提案する + ダウンロードが開始されました + 言語 + ソースが無効になっています + 現在としてマーク + ログ記録を有効にする + 疑わしいコンテンツを表示する + ダイナミック + 配色 + グリッドビューで表示 + アスカ + ミオン + リッカ + さくら + この変更を適用するには、アプリケーションを再起動してください + 項目をタップ&ホールドして並び替えをすることができます + .cbzまたは.zipファイルを1つ以上選択することができ、各ファイルは別のマンガとして認識されます。 + 了解 + 翻訳 + 過去に作成したユーザーデータのバックアップをインポートする + 棚に表示 + %1$s (%2$s) + 色を反転させる + 有効 + 結構です + ネットワークキャッシュをクリアする + ダウンロードは削除されました + 自分で用意した同期サーバーか、デフォルトのものを使用することができます。よく分からない場合は変更しないでください。 + 一時停止 + ダウンロードがキャンセルされました + WebViewが利用できません:WebView providerがインストールされているかどうかを確認してください + ダウンロード済み + 画像最適化プロキシ + wsrv.nl サービスを使用して、トラフィック使用量を削減し、可能であれば画像の読み込みを高速化します + アーカイブや画像のあるディレクトリを選択することができます。各アーカイブ(またはサブディレクトリ)は、1つのチャプターとして認識されます。 + 類似したものを探す + タイプ + アドレス + ポート + プロキシ + 同期の設定 + サーバーアドレス + 速度 + SSLエラーを無視する + ミラーを自動的に選択する + ミラーがある場合、エラー時にリモートソースのドメインを自動で切り替える + 履歴書 + 一時停止 + 全てキャンセル + Wi-Fi経由でのみダウンロード + モバイルデータ通信への切り替え時にダウンロードを停止する + 提案: %s + 提案されたマンガの通知を表示することがあります + もっと見る + アクティブなダウンロードはすべてキャンセルされ、部分的にダウンロードされたデータは失われます + ダウンロード履歴は完全に削除されます + ダウンロードはありません + ダウンロードが再開されました + ダウンロードが一時停止されました + パーソナライズされた漫画の提案を受け取りますか? + 削除が完了 + 既存のアカウントにサインインするか、新規にアカウントを作成することができます + 無効な値 + ユーザー名 + パスワード + オーソライズ(オプション) + diff --git a/app/src/main/res/values-kk/strings.xml b/app/src/main/res/values-kk/strings.xml index 0eda0d4ec..da52aec1e 100644 --- a/app/src/main/res/values-kk/strings.xml +++ b/app/src/main/res/values-kk/strings.xml @@ -58,7 +58,6 @@ Суретті бөлісу Импорт Сипаттамасы жоқ - Тарих пен кәш Б|кБ|МБ|ГБ|ТБ Стандарт Уебтүн diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index d5a6ea14f..162338c1b 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -51,7 +51,6 @@ 저장됨 이미지 공유하기 ZIP 혹은 CBZ 파일을 선택하세요. - 기록 및 캐시 만화 제거 볼륨 키 결과 없음 @@ -202,7 +201,6 @@ 모든 검색 기록을 영구적으로 삭제 하시겠어요\? 더 읽기 대기열 - 이 챕터는 다운로드 하거나 온라인으로 읽어야 합니다. 모든 사이트에서 로그아웃됩니다 장르 완료됨 @@ -218,13 +216,11 @@ 아무 만화나 읽어보세요 당신의 기록을 바탕으로 개인화된 추천 만화를 제공합니다 활성화됨 필터 초기화 - 장르 찾기 와이파이에 연결된 경우에만 항상 무슨 언어의 만화를 읽을지 선택하세요. 나중에 설정에서 이를 변경할 수 있습니다. 18+ %1$s%% - 컨텐츠 페이지 미리 로드하기 %s로 로그인 됨 외관 diff --git a/app/src/main/res/values-nb-rNO/plurals.xml b/app/src/main/res/values-nb-rNO/plurals.xml index 0b7aaadbf..4659237c8 100644 --- a/app/src/main/res/values-nb-rNO/plurals.xml +++ b/app/src/main/res/values-nb-rNO/plurals.xml @@ -1,9 +1,5 @@ - - Totalt %1$d side - Totalt %1$d sider - %1$d nytt kapittel %1$d nye kapitler diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 80395c7b4..4884bfd7b 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -53,7 +53,6 @@ Nettserie Forvalg Tøm sidehurtiglager - Historikk og hurtiglager Velg en ZIP- eller CBZ-fil. Ustøttet handling Importer @@ -181,7 +180,6 @@ Historikk Favoritter Lokallagring - Last ned eller les dette manglende kapittelet på nett. Kapittelet mangler I kø Fullført @@ -214,7 +212,6 @@ Alltid Forhåndsinnlast bilder Tilbakestill filter - Finn sjanger Aldri Kun på Wi-Fi Velg språkene du ønsker å lese manga. Du kan endre dette senere i innstillingene. @@ -224,7 +221,6 @@ %1$s%% Forskjellige språk Ingen kapitler i denne mangaen - Innhold Utseende Navn Rediger diff --git a/app/src/main/res/values-ne/plurals.xml b/app/src/main/res/values-ne/plurals.xml index 67fc0c98b..b140ecec1 100644 --- a/app/src/main/res/values-ne/plurals.xml +++ b/app/src/main/res/values-ne/plurals.xml @@ -1,9 +1,5 @@ - - कुल %1$d पृष्ठ - कुल %1$d पृष्ठहरू - %1$d नयाँ अध्याय %1$d नयाँ अध्यायहरू diff --git a/app/src/main/res/values-ne/strings.xml b/app/src/main/res/values-ne/strings.xml index 446981da9..4d4df7987 100644 --- a/app/src/main/res/values-ne/strings.xml +++ b/app/src/main/res/values-ne/strings.xml @@ -1,142 +1,141 @@ - डाउनलोड गर्दै… - डाउनलोड गरेको - फिल्टर - अँध्यारो - खाली गर्नुहोस् - पृष्ठहरू - एउटा त्रुटि भयो - सूची मोड - सूची - पुनः प्रयास गर्नुहोस् - केही पनि फेला परेन - पढ्नुहोस् - लोकल भण्डारण - इतिहास - नेटवर्क त्रुटि - अध्यायहरू - सेटिङहरू - माङ्गा स्रोतहरू - लोड हुँदै… - इतिहास खाली गर्नुहोस् - अहिले कुनै मनपर्ने छैन - मनपर्ने मा राख्नुहोस् - नयाँ वर्ग - %s साझा गर्नुहोस् - खोज्नुहोस् - माङ्गा खोज्नुहोस् - प्रक्रिया गर्दैछ… - डाउनलोडहरू - नाम - अपडेट गरिएको - नवीनतम - क्रमबद्ध क्रम - थीम - उज्यालो - सिस्टम पालना गर्नुहोस् - कम्प्युटिङ… - मनपर्नेहरू - विवरणहरू - विस्तृत सूची - ग्रिड - %2$d को अध्याय %1$d - बन्द गर्नुहोस् - अहिलेसम्म इतिहास छैन - थप्नुहोस् - बचत गर्नुहोस् - साझा गर्नुहोस् - सर्टकट सिर्जना गर्नुहोस्… - लोकप्रिय - मूल्याङ्कन - नयाँ अध्यायहरू - सबै पढेको इतिहास स्थायी रूपमा खाली गर्ने हो\? - हटाउनुहोस् - लोकल भण्डारणबाट %s हटाइयो - सेभ गरियो - पृष्ठ सेभ गर्नुहोस् - छवि साझा गर्नुहोस् - आयात गर्नुहोस् - स्ट्यानडर्ड - वेबटून - पढ्ने मोड - ग्रिड साइज - यन्त्रबाट %s स्थायी रूपमा हटाउने हो\? - रिडर सेटिङहरू - %s मा खोज्नुहोस् - माङ्गा हटाउनुहोस् - पृष्ठ स्विच गर्नुहोस् - किनारा ट्यापहरू - भोल्युम बटन - जारी राख्नुहोस् - त्रुटि - खाली गरियो - जेस्चर मात्र - थम्बनेल क्यास खाली गर्नुहोस् - खोज इतिहास खाली गर्नुहोस् - डोमेन - यो माङ्गामा %s छ। यो सबै सेभ गर्ने\? - आन्तरिक भण्डारण - एपको नयाँ संस्करण उपलब्ध छ - बाह्य भण्डारण - वेब ब्राउजरमा खोल्नुहोस् - डाउनलोड - सूचना सेटिङ - LED सूचक - भाईब्रेशन - मनपर्ने वर्गहरू - हटाउनुहोस् - यहाँ अलि खाली जस्तो छ… - सोधपुछ सुधार गर्ने प्रयास गर्नुहोस्। - तपाईँले पढेको कुरा यहाँ देखाइनेछ - साइड मेनुमा के पढ्ने फेला पार्नुहोस्। - पृष्ठ एनिमेसन - डाउनलोडका लागि फोल्डर - हालैका - उपलब्ध छैन - तपाईंले पढिरहनु भएको माङ्गाको नयाँ अध्यायहरू यहाँ देखाइएको छ - खोज परिणामहरू - अपडेट फिड खाली गर्नुहोस् - स्क्रिन घुमाउनुहोस् - अपडेट - पासवर्डहरू म्याच गरेनन् - बारेमा - संस्करण %s - यो अपरेशन समर्थित छैन - कुनै विवरण छैन - इतिहास र क्यास - पृष्ठ क्यास खाली गर्नुहोस् - सूचना आवाज - पहिले केही सेभ गर्नुहोस् - यसलाई अनलाइन स्रोतहरूबाट सेभ गर्नुहोस् वा फाइलहरू आयात गर्नुहोस्। - खाली गरियो - एप सुरक्षित गर्नुहोस् - Kotatsu सुरु गर्दा पासवर्ड माग्नुहोस् - पासवर्ड दोहोर्याउनुहोस् - हटाउनुहोस् - या त ZIP वा CBZ फाइल छान्नुहोस्। - B|kB|MB|GB|TB - सेभ - सूचनाहरू - %2$d को %1$d अन - तपाईंको माङ्गा यहाँ देखाउनेछ - «अन्वेषण» भागमा के पढ्ने फेला पार्नुहोस् - दराज - भण्डारण उपलब्ध छैन - अन्य भण्डारण - सकियो - सबै मनपर्नेहरू - खाली वर्ग - पछि पढ्ने - अपडेटहरू - नयाँ संस्करण: %s - साइज: %s - फिड अपडेट चाँडै सुरु हुनेछ - अपडेटहरू खोज्नुहोस् - जाँच नगर्नुहोस् - गलत पासवर्ड - अपडेटका लागि जाँच गर्नुहोस् - कुनै अपडेट उपलब्ध छैन - अन्वेषण - पासवर्ड एन्टर गर्नुहोस् - \ No newline at end of file + डाउनलोड गर्दै… + डाउनलोड गरेको + फिल्टर + अँध्यारो + खाली गर्नुहोस् + पृष्ठहरू + एउटा त्रुटि भयो + सूची मोड + सूची + पुनः प्रयास गर्नुहोस् + केही पनि फेला परेन + पढ्नुहोस् + लोकल भण्डारण + इतिहास + नेटवर्क त्रुटि + अध्यायहरू + सेटिङहरू + माङ्गा स्रोतहरू + लोड हुँदै… + इतिहास खाली गर्नुहोस् + अहिले कुनै मनपर्ने छैन + मनपर्ने मा राख्नुहोस् + नयाँ वर्ग + %s साझा गर्नुहोस् + खोज्नुहोस् + माङ्गा खोज्नुहोस् + प्रक्रिया गर्दैछ… + डाउनलोडहरू + नाम + अपडेट गरिएको + नवीनतम + क्रमबद्ध क्रम + थीम + उज्यालो + सिस्टम पालना गर्नुहोस् + कम्प्युटिङ… + मनपर्नेहरू + विवरणहरू + विस्तृत सूची + ग्रिड + %2$d को अध्याय %1$d + बन्द गर्नुहोस् + अहिलेसम्म इतिहास छैन + थप्नुहोस् + बचत गर्नुहोस् + साझा गर्नुहोस् + सर्टकट सिर्जना गर्नुहोस्… + लोकप्रिय + मूल्याङ्कन + नयाँ अध्यायहरू + सबै पढेको इतिहास स्थायी रूपमा खाली गर्ने हो\? + हटाउनुहोस् + लोकल भण्डारणबाट %s हटाइयो + सेभ गरियो + पृष्ठ सेभ गर्नुहोस् + छवि साझा गर्नुहोस् + आयात गर्नुहोस् + स्ट्यानडर्ड + वेबटून + पढ्ने मोड + ग्रिड साइज + यन्त्रबाट %s स्थायी रूपमा हटाउने हो\? + रिडर सेटिङहरू + %s मा खोज्नुहोस् + माङ्गा हटाउनुहोस् + पृष्ठ स्विच गर्नुहोस् + किनारा ट्यापहरू + भोल्युम बटन + जारी राख्नुहोस् + त्रुटि + खाली गरियो + जेस्चर मात्र + थम्बनेल क्यास खाली गर्नुहोस् + खोज इतिहास खाली गर्नुहोस् + डोमेन + यो माङ्गामा %s छ। यो सबै सेभ गर्ने\? + आन्तरिक भण्डारण + एपको नयाँ संस्करण उपलब्ध छ + बाह्य भण्डारण + वेब ब्राउजरमा खोल्नुहोस् + डाउनलोड + सूचना सेटिङ + LED सूचक + भाईब्रेशन + मनपर्ने वर्गहरू + हटाउनुहोस् + यहाँ अलि खाली जस्तो छ… + सोधपुछ सुधार गर्ने प्रयास गर्नुहोस्। + तपाईँले पढेको कुरा यहाँ देखाइनेछ + साइड मेनुमा के पढ्ने फेला पार्नुहोस्। + पृष्ठ एनिमेसन + डाउनलोडका लागि फोल्डर + हालैका + उपलब्ध छैन + तपाईंले पढिरहनु भएको माङ्गाको नयाँ अध्यायहरू यहाँ देखाइएको छ + खोज परिणामहरू + अपडेट फिड खाली गर्नुहोस् + स्क्रिन घुमाउनुहोस् + अपडेट + पासवर्डहरू म्याच गरेनन् + बारेमा + संस्करण %s + यो अपरेशन समर्थित छैन + कुनै विवरण छैन + पृष्ठ क्यास खाली गर्नुहोस् + सूचना आवाज + पहिले केही सेभ गर्नुहोस् + यसलाई अनलाइन स्रोतहरूबाट सेभ गर्नुहोस् वा फाइलहरू आयात गर्नुहोस्। + खाली गरियो + एप सुरक्षित गर्नुहोस् + Kotatsu सुरु गर्दा पासवर्ड माग्नुहोस् + पासवर्ड दोहोर्याउनुहोस् + हटाउनुहोस् + या त ZIP वा CBZ फाइल छान्नुहोस्। + B|kB|MB|GB|TB + सेभ + सूचनाहरू + %2$d को %1$d अन + तपाईंको माङ्गा यहाँ देखाउनेछ + «अन्वेषण» भागमा के पढ्ने फेला पार्नुहोस् + दराज + भण्डारण उपलब्ध छैन + अन्य भण्डारण + सकियो + सबै मनपर्नेहरू + खाली वर्ग + पछि पढ्ने + अपडेटहरू + नयाँ संस्करण: %s + साइज: %s + फिड अपडेट चाँडै सुरु हुनेछ + अपडेटहरू खोज्नुहोस् + जाँच नगर्नुहोस् + गलत पासवर्ड + अपडेटका लागि जाँच गर्नुहोस् + कुनै अपडेट उपलब्ध छैन + अन्वेषण + पासवर्ड एन्टर गर्नुहोस् + diff --git a/app/src/main/res/values-nn/plurals.xml b/app/src/main/res/values-nn/plurals.xml index ed6c18ca4..c0fc3296b 100644 --- a/app/src/main/res/values-nn/plurals.xml +++ b/app/src/main/res/values-nn/plurals.xml @@ -16,10 +16,6 @@ %1$d element %1$d element - - I alt %1$d side - I alt %1$d sider - %1$d nytt kapittel %1$d nye kapittel diff --git a/app/src/main/res/values-nn/strings.xml b/app/src/main/res/values-nn/strings.xml index 905125266..52fa0b42f 100644 --- a/app/src/main/res/values-nn/strings.xml +++ b/app/src/main/res/values-nn/strings.xml @@ -1,362 +1,358 @@ - Det hende ein feil - Rutenett - Innstillingar - Mangakjelder - Tøm historikken - Historikken er tom - Les - Lik - Ny hop - Legg til - Hent - Lag ein snarveg … - Del %s - Søk - Søk manga - Hentar … - Handsamar … - Henta - Nyaste - Omdøme - Sil ut - Ljos - Sider - Tøm - Tøm lesehistorikken for godt\? - Tak bort - Hent sida - Henta - Del biletet - Før inn - Slett - Vel ei ZIP- eller CBZ-fil. - Ingen utgreiing - Tøm mellomminnet til sida - Vanleg - Nettserie - Rutenettstorleik - Slett mangaen - Slett «%s» ifrå eininga\? - Leseinnstillingar - Bla med - Hald fram - Feil - Tøm mellomminnet for småbilete - Tøm søkehistorikken - Tømt - Berre handvendingar - Hent - Varsel - %1$d av %2$d - Hent - Varselinnstillingar - Varselljod - Varselljos - Dirring - Hopar til leiting - Hent ifrå nettkjelder eller før inn filer. - Hylla - Nytt - Legg henta mangaar i: - Ferdig - Alt du likar - Tom hop - Les seinare - Oppdateringar - Søkesvar - Ny utgåve: %s - Tømt - Snu skjermen - Leit etter oppdateringar - Nei - Om - Leit etter oppdateringar - Høgre-til-venstre - Lesevising - Høv til høgda - Høv til breidda - Svart - Tryggleikskopiering og gjenoppretting - Lag ein tryggleikskopi - Gjenoppretta - Fann ikkje fila - Gjenoppretta all data - Gjenoppretta dataa, men med feil - Trykk for å røyna att - Listeslag - Henta - Likar - Historikk - Nettverksfeil - Liste - Hentar fram … - Steng - Røyn att - Fann ikkje noko - Del - Henta - Namn - Oppdatert - Vising - Lyd systemet - Mørk - Historikken og mellomminnet - Hent noko først - Ikkje tilgjengeleg - Oppdater - Storleik: %s - Brukar mindre straum på AMOLED-skjermar - Utgåve %s - Ingen tilgjengelege oppdateringar - Ny hop - Midtstill - Auk byrjinga av sida - Gjenopprett ifrå ein tryggleikskopi - Du kan tryggleikskopiera historikken og likerlista di til seinare gjenoppretting - Førebur … - Forval - No - I dag - I går - Lenge sida - Lesing - Randetrykk - Ljodstyrkeknappar - Ei ny utgåve av appen er tilgjengeleg - Opne i ein nettlesar - Denne mangaen har %s. Hent alle\? - Det du les vert vist her - Rit inn lykelordet - Gjentak lykelordet - Lykelorda er ulike - Brigde av oppsettet vedkjem berre denne mangaen - Stille - Krev CAPTCHA - Løys - Slett infokapslane - Sletta infokapslane - Tøm oppdateringshistorikken\? - Logg inn - Neste - Stadfest - Lykelordet må vera lengre enn fire teikn - Tryggleikskopi laga - Les meir - I kø - Omset denne appen - Omsetjing - Godkjend - Slag - Fullgjort - I gang - Utelèt mangaar med vakse innhald ifrå historikken - Sidetal - Nytta kjelder - Tilgjengelege kjelder - Skjermbilete - Hindre alltid - Råd - Slå på råd - Rå om mangaar ut ifrå det du har lese - Byrja å lesa nokre mangaar for å få personlege råd - Ikkje rå mangaar med vakse innhald - Påslegen - Kunne ikkje hente inn slaglista - Finn slag - Ulike mål - %1$s%% - Innhald - Oppdaterer råd - Utelat slag - Sletta - Avgrens hentesnøggleiken - Lægjer vona for at IP-adressa di vert blokkert - Handsamar henta manga - Avbroten - Kontoen finst alt - Attende - Synkroniser dataet ditt - Rit inn e-postadressa di for å halda fram - Skjul - Namn - Brigd - Brigd hopen - Sporing - Ingen likte hopar - Logg ut - Bokmerk - Tak bort bokmerket - Bokmerke - Teken bort ifrå historikken - DNS over HTTPS - Forvald lesing - Finn sjølvverkande ut av lesing - Finn sjølvverkande ut av om mangaen er ein nettserie - Slå av batterilenging - Send - Les - Skal lesa - Les att - Lesen - På vent - Gjeven opp - Slå av alle - Mangaar du har nyleg lese - Sletting av data - Vis % lesen i historikken og likerlista - Kan løysa nokre feil. Alle godkjenningar vert ugilde - Vis alle - Ugildt domene - Vel område - Tøm heile historikken - Tømte historikken - Ingen bokmerke endå - Du kan lage bokmerke medan du les - Tok bort bokmerka - Ingen mangakjelder - Slå på minst ei mangakjelde for å lesa mangaar på nett - Tilfeldig - Flytt - Tom - Trykk Attende att for å gå or appen - Utgåingsstadfesting - Mellominnet for sider - Mellomminnet for anna - Tilgjengeleg - %s - %s - Teken or likerlista - Fann ikkje innhaldet - Bla sjølvverkande - Teikneseriearkiv - Mappe med bilete - Fører inn manga - Brigd letar - Ljosstyrk - Still attende - Spar eller avvis dei usparte brigda\? - Avvis - Eininga er fylt - Vis ei rulleline til blading - Auk/mink nettseriar - Ulike mål - Nettverk ikkje tilgjengeleg - Slå på Wi-Fi eller mobilnettverk for å lesa mangaar på nett - Tjenarfeil (%1$d). Røyn att seinare - Kjelde avslegen - Hent inn innhald på forhand - Merk som aktuelt - Mål - Del loggføringar - Slå på loggføring - Tak opp nokre gjerder til bruk i istandsetjing. - Skiftande - Letar - Vis som rutenett - Rikka - Asuka - Sakura - Mamimi - Kanade - Ingenting her - Tenester - Har byrja å hente - Tøm søkehistorikken\? - Velkomen - Du vert logga ut ifrå alle kjeldane - Hindre ved vakse innhald - Slett - Her var det tomt … - Spør om lykelordet ved byrjing av appen - Feil lykelord - Vern appen - Logg inn for å sjå dette innhaldet - Vern appen med eit lykelord - All data vert handsama på eininga di og vert ikkje førte over til noka teneste - Avslegen - Vel måla du vil lesa mangaar på. Du kan brigde på dette seinare i innstillingane. - Aldri - Berre på Wi-Fi - 18+ - Alltid - Hent sider på forhand - Utsjånaden - Slett valde ting ifrå eininga di\? - Logga inn som %s - Opplys om kva slags slag du ikkje vil få råd om - Synkronisering - Nye mangakjelder tilgjengelege - Du kjem til å få varsel når mangaar du les vert oppdaterte - Slå på varsel - La til eit bokmerke - Tok bort bokmerket - Angre - Nytt fingermerke om tilgjengeleg - Vis leseframgang - Mangaar du likar - Mangaar merkte med vakse innhald vert ikkje lagde til i historikken din, og framgangen din vert ikkje spart - Slett dei valde hopane\? + Det hende ein feil + Rutenett + Innstillingar + Mangakjelder + Tøm historikken + Historikken er tom + Les + Lik + Ny hop + Legg til + Hent + Lag ein snarveg … + Del %s + Søk + Søk manga + Hentar … + Handsamar … + Henta + Nyaste + Omdøme + Sil ut + Ljos + Sider + Tøm + Tøm lesehistorikken for godt\? + Tak bort + Hent sida + Henta + Del biletet + Før inn + Slett + Vel ei ZIP- eller CBZ-fil. + Ingen utgreiing + Tøm mellomminnet til sida + Vanleg + Nettserie + Rutenettstorleik + Slett mangaen + Slett «%s» ifrå eininga\? + Leseinnstillingar + Bla med + Hald fram + Feil + Tøm mellomminnet for småbilete + Tøm søkehistorikken + Tømt + Berre handvendingar + Hent + Varsel + %1$d av %2$d + Hent + Varselinnstillingar + Varselljod + Varselljos + Dirring + Hopar til leiting + Hent ifrå nettkjelder eller før inn filer. + Hylla + Nytt + Legg henta mangaar i: + Ferdig + Alt du likar + Tom hop + Les seinare + Oppdateringar + Søkesvar + Ny utgåve: %s + Tømt + Snu skjermen + Leit etter oppdateringar + Nei + Om + Leit etter oppdateringar + Høgre-til-venstre + Lesevising + Høv til høgda + Høv til breidda + Svart + Tryggleikskopiering og gjenoppretting + Lag ein tryggleikskopi + Gjenoppretta + Fann ikkje fila + Gjenoppretta all data + Gjenoppretta dataa, men med feil + Trykk for å røyna att + Listeslag + Henta + Likar + Historikk + Nettverksfeil + Liste + Hentar fram … + Steng + Røyn att + Fann ikkje noko + Del + Henta + Namn + Oppdatert + Vising + Lyd systemet + Mørk + Hent noko først + Ikkje tilgjengeleg + Oppdater + Storleik: %s + Brukar mindre straum på AMOLED-skjermar + Utgåve %s + Ingen tilgjengelege oppdateringar + Ny hop + Midtstill + Auk byrjinga av sida + Gjenopprett ifrå ein tryggleikskopi + Du kan tryggleikskopiera historikken og likerlista di til seinare gjenoppretting + Førebur … + Forval + No + I dag + I går + Lenge sida + Lesing + Randetrykk + Ljodstyrkeknappar + Ei ny utgåve av appen er tilgjengeleg + Opne i ein nettlesar + Denne mangaen har %s. Hent alle\? + Det du les vert vist her + Rit inn lykelordet + Gjentak lykelordet + Lykelorda er ulike + Brigde av oppsettet vedkjem berre denne mangaen + Stille + Krev CAPTCHA + Løys + Slett infokapslane + Sletta infokapslane + Tøm oppdateringshistorikken\? + Logg inn + Neste + Stadfest + Lykelordet må vera lengre enn fire teikn + Tryggleikskopi laga + Les meir + I kø + Omset denne appen + Omsetjing + Godkjend + Slag + Fullgjort + I gang + Utelèt mangaar med vakse innhald ifrå historikken + Sidetal + Nytta kjelder + Tilgjengelege kjelder + Skjermbilete + Hindre alltid + Råd + Slå på råd + Rå om mangaar ut ifrå det du har lese + Byrja å lesa nokre mangaar for å få personlege råd + Ikkje rå mangaar med vakse innhald + Påslegen + Kunne ikkje hente inn slaglista + Ulike mål + %1$s%% + Oppdaterer råd + Utelat slag + Sletta + Avgrens hentesnøggleiken + Lægjer vona for at IP-adressa di vert blokkert + Handsamar henta manga + Avbroten + Kontoen finst alt + Attende + Synkroniser dataet ditt + Rit inn e-postadressa di for å halda fram + Skjul + Namn + Brigd + Brigd hopen + Sporing + Ingen likte hopar + Logg ut + Bokmerk + Tak bort bokmerket + Bokmerke + Teken bort ifrå historikken + DNS over HTTPS + Forvald lesing + Finn sjølvverkande ut av lesing + Finn sjølvverkande ut av om mangaen er ein nettserie + Slå av batterilenging + Send + Les + Skal lesa + Les att + Lesen + På vent + Gjeven opp + Slå av alle + Mangaar du har nyleg lese + Sletting av data + Vis % lesen i historikken og likerlista + Kan løysa nokre feil. Alle godkjenningar vert ugilde + Vis alle + Ugildt domene + Vel område + Tøm heile historikken + Tømte historikken + Ingen bokmerke endå + Du kan lage bokmerke medan du les + Tok bort bokmerka + Ingen mangakjelder + Slå på minst ei mangakjelde for å lesa mangaar på nett + Tilfeldig + Flytt + Tom + Trykk Attende att for å gå or appen + Utgåingsstadfesting + Mellominnet for sider + Mellomminnet for anna + Tilgjengeleg + %s - %s + Teken or likerlista + Fann ikkje innhaldet + Bla sjølvverkande + Teikneseriearkiv + Mappe med bilete + Fører inn manga + Brigd letar + Ljosstyrk + Still attende + Spar eller avvis dei usparte brigda\? + Avvis + Eininga er fylt + Vis ei rulleline til blading + Auk/mink nettseriar + Ulike mål + Nettverk ikkje tilgjengeleg + Slå på Wi-Fi eller mobilnettverk for å lesa mangaar på nett + Tjenarfeil (%1$d). Røyn att seinare + Kjelde avslegen + Hent inn innhald på forhand + Merk som aktuelt + Mål + Del loggføringar + Slå på loggføring + Tak opp nokre gjerder til bruk i istandsetjing. + Skiftande + Letar + Vis som rutenett + Rikka + Asuka + Sakura + Mamimi + Kanade + Ingenting her + Tenester + Har byrja å hente + Tøm søkehistorikken\? + Velkomen + Du vert logga ut ifrå alle kjeldane + Hindre ved vakse innhald + Slett + Her var det tomt … + Spør om lykelordet ved byrjing av appen + Feil lykelord + Vern appen + Logg inn for å sjå dette innhaldet + Vern appen med eit lykelord + All data vert handsama på eininga di og vert ikkje førte over til noka teneste + Avslegen + Vel måla du vil lesa mangaar på. Du kan brigde på dette seinare i innstillingane. + Aldri + Berre på Wi-Fi + 18+ + Alltid + Hent sider på forhand + Utsjånaden + Slett valde ting ifrå eininga di\? + Logga inn som %s + Opplys om kva slags slag du ikkje vil få råd om + Synkronisering + Nye mangakjelder tilgjengelege + Du kjem til å få varsel når mangaar du les vert oppdaterte + Slå på varsel + La til eit bokmerke + Tok bort bokmerket + Angre + Nytt fingermerke om tilgjengeleg + Vis leseframgang + Mangaar du likar + Mangaar merkte med vakse innhald vert ikkje lagde til i historikken din, og framgangen din vert ikkje spart + Slett dei valde hopane\? \nDu kan ikkje angre. Alle mangaane inni vert tekne ut av likerlista. - Innstillingar - Dei siste to timane - Handsam - Trykk Attende to gongar for å gå or appen - Henta mangaar - Privat modus - Førte inn - Slett den opphavlege fila for å frigjera rom - Byrjar å føra inn snart - Motsetjing - Brigde av letane vedkjem berre denne mangaen - Vis mistenksamt innhald - Mion - Miku - Byrja om appen for å nytta desse brigda - Kapittel - Utreknar… - Kapittel %1$d av %2$d - Ustødd gjerd - B|kB|MB|GB|TB - Domene - Nye kapittel - Mangaane dine vert viste her - Siderørsle - Nye kapittel av det du les vert viste her - Sjå etter nye kapittel - Siste øvst - Nokre einingar har systemåtferd som kan knuse bakgrunnsføreloger. - Hent eller les dette saknande kapittelet på nettet. - Saknar kapittelet - Finn kapittel - Ingen kapittel i denne mangaen - Kapittel vert teken bort i bakgrunnen - Sjå etter og varsle om nye kapittel - Nye kapittel vert merkte i listene utan varsel - Gransk - Ingen kapittel - Ka. %1$d/%2$d Side %3$d/%4$d - Vis opplysingsområde i lesevisinga - Trykk på høgre side eller ljodstyrke-ned-knappen blar alltid til neste side - Samantrengt - Vis i hylla - Før inn ei tryggleikskopi av brukardata - Du kan velja ei mappe med arkiv eller bilete. Kvart arkiv (eller undermappe) vert tydde som eit kapittel. - Snøggleik - Vel ei eller fleire .cbz eller .zip-filer, kvar fil vert tydde som ein eigen manga. - Tøm au opplysingar om nye kapittel - Trykk «Meny → Spor» på ei mangadetaljside for å spore leseframdrifta. - Skjønar - Trykk og hald på eit element for å flytta på det - Sletta «%s» ifrå eininga - Indre gøyme - Ytre gøyme - Ingen tilgjengelege gøyme - Anna gøyme - Røyn å skriva det om. - Ingen likte enno - Mest lest for tida - Søk på %s - Finn lesnadar i sidemenyen. - Finn lesnadar i «Gransk»-delen - \ No newline at end of file + Innstillingar + Dei siste to timane + Handsam + Trykk Attende to gongar for å gå or appen + Henta mangaar + Privat modus + Førte inn + Slett den opphavlege fila for å frigjera rom + Byrjar å føra inn snart + Motsetjing + Brigde av letane vedkjem berre denne mangaen + Vis mistenksamt innhald + Mion + Miku + Byrja om appen for å nytta desse brigda + Kapittel + Utreknar… + Kapittel %1$d av %2$d + Ustødd gjerd + B|kB|MB|GB|TB + Domene + Nye kapittel + Mangaane dine vert viste her + Siderørsle + Nye kapittel av det du les vert viste her + Sjå etter nye kapittel + Siste øvst + Nokre einingar har systemåtferd som kan knuse bakgrunnsføreloger. + Saknar kapittelet + Finn kapittel + Ingen kapittel i denne mangaen + Kapittel vert teken bort i bakgrunnen + Sjå etter og varsle om nye kapittel + Nye kapittel vert merkte i listene utan varsel + Gransk + Ingen kapittel + Ka. %1$d/%2$d Side %3$d/%4$d + Vis opplysingsområde i lesevisinga + Trykk på høgre side eller ljodstyrke-ned-knappen blar alltid til neste side + Samantrengt + Vis i hylla + Før inn ei tryggleikskopi av brukardata + Du kan velja ei mappe med arkiv eller bilete. Kvart arkiv (eller undermappe) vert tydde som eit kapittel. + Snøggleik + Vel ei eller fleire .cbz eller .zip-filer, kvar fil vert tydde som ein eigen manga. + Tøm au opplysingar om nye kapittel + Trykk «Meny → Spor» på ei mangadetaljside for å spore leseframdrifta. + Skjønar + Trykk og hald på eit element for å flytta på det + Sletta «%s» ifrå eininga + Indre gøyme + Ytre gøyme + Ingen tilgjengelege gøyme + Anna gøyme + Røyn å skriva det om. + Ingen likte enno + Mest lest for tida + Søk på %s + Finn lesnadar i sidemenyen. + Finn lesnadar i «Gransk»-delen + diff --git a/app/src/main/res/values-or/plurals.xml b/app/src/main/res/values-or/plurals.xml index 9a190afa8..3c8d454dd 100644 --- a/app/src/main/res/values-or/plurals.xml +++ b/app/src/main/res/values-or/plurals.xml @@ -1,27 +1,23 @@ - - %1$d ମିନିଟ୍ ପୂର୍ଵେ - %1$d ମିନିଟ୍ ପୂର୍ଵେ - - - %1$d ଦିନ ପୂର୍ଵେ - %1$d ଦିନ ପୂର୍ଵେ - - - %1$dଟିଏ ନୂଆ ଅଧ୍ୟାୟ - %1$dଟି ନୂଆ ଅଧ୍ୟାୟ - - - ମୋଟ %1$dଟିଏ ପୃଷ୍ଠା - ମୋଟ %1$dଟି ପୃଷ୍ଠା - - - %1$d ଘଣ୍ଟା ପୂର୍ଵେ - %1$d ଘଣ୍ଟା ପୂର୍ଵେ - - - %1$dଟିଏ ଅଧ୍ୟାୟ - %1$dଟି ଅଧ୍ୟାୟ - - \ No newline at end of file + + %1$d ମିନିଟ୍ ପୂର୍ଵେ + %1$d ମିନିଟ୍ ପୂର୍ଵେ + + + %1$d ଦିନ ପୂର୍ଵେ + %1$d ଦିନ ପୂର୍ଵେ + + + %1$dଟିଏ ନୂଆ ଅଧ୍ୟାୟ + %1$dଟି ନୂଆ ଅଧ୍ୟାୟ + + + %1$d ଘଣ୍ଟା ପୂର୍ଵେ + %1$d ଘଣ୍ଟା ପୂର୍ଵେ + + + %1$dଟିଏ ଅଧ୍ୟାୟ + %1$dଟି ଅଧ୍ୟାୟ + + diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index b55162b4b..0e883613f 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -1,29 +1,28 @@ - ଇତିଵୃତ୍ତି - ଵିଵରଣୀ - ସେଟିଂ - ପରାମର୍ଶ: %s - ହେଲା - ସେଵା - ବୁଝିଗଲି - କଳା - ଥିମ୍ - ଵେଗ - ଡାଉନଲୋଡ୍ ଆରମ୍ଭ ହେଲା - ପାଠକ ସେଟିଂ - ଵିଜ୍ଞପ୍ତି - ଥାକ - ସର୍ଵଦା - ଵିଷୟଵସ୍ତୁ - ଵିଜ୍ଞପ୍ତି ସେଟିଂ - ରୂପ - ଯାଞ୍ଚ କରନି - ଅଦ୍ୟତନ ପାଇଁ ଯାଞ୍ଚ କରିବା - ଗତକାଲି - ଆଜି - ନୂଆ ଅଧ୍ୟାୟ ପାଇଁ ଯାଞ୍ଚ କରି ଏହା ଵିଷୟରେ ସୂଚିତ କରିବା - ନୂଆ ଅଧ୍ୟାୟ ପାଇଁ ଯାଞ୍ଚ କରିବା - ଫାଇଲ ମିଳୁନାହିଁ - ବ୍ୟାକଅପ୍ ଓ ପୁନରୁଦ୍ଧାର - \ No newline at end of file + ଇତିଵୃତ୍ତି + ଵିଵରଣୀ + ସେଟିଂ + ପରାମର୍ଶ: %s + ହେଲା + ସେଵା + ବୁଝିଗଲି + କଳା + ଥିମ୍ + ଵେଗ + ଡାଉନଲୋଡ୍ ଆରମ୍ଭ ହେଲା + ପାଠକ ସେଟିଂ + ଵିଜ୍ଞପ୍ତି + ଥାକ + ସର୍ଵଦା + ଵିଜ୍ଞପ୍ତି ସେଟିଂ + ରୂପ + ଯାଞ୍ଚ କରନି + ଅଦ୍ୟତନ ପାଇଁ ଯାଞ୍ଚ କରିବା + ଗତକାଲି + ଆଜି + ନୂଆ ଅଧ୍ୟାୟ ପାଇଁ ଯାଞ୍ଚ କରି ଏହା ଵିଷୟରେ ସୂଚିତ କରିବା + ନୂଆ ଅଧ୍ୟାୟ ପାଇଁ ଯାଞ୍ଚ କରିବା + ଫାଇଲ ମିଳୁନାହିଁ + ବ୍ୟାକଅପ୍ ଓ ପୁନରୁଦ୍ଧାର + diff --git a/app/src/main/res/values-pl/plurals.xml b/app/src/main/res/values-pl/plurals.xml index 2779a1496..8a68c940e 100644 --- a/app/src/main/res/values-pl/plurals.xml +++ b/app/src/main/res/values-pl/plurals.xml @@ -10,11 +10,6 @@ %1$d minuty temu %1$d minut temu - - Łącznie %1$d strona - Łącznie %1$d strony - Łącznie %1$d stron - %1$d godzinę temu %1$d godziny temu diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 9dc982b98..e99ab579a 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1,420 +1,416 @@ - Ulubione - Historia - Napotkano błąd - Szczegółowy - Rozdziały - Lista - Lista szczegółowa - Siatka - Tryb listy - Ustawienia - Ładowanie… - Rozdział %1$d z %2$d - Zamknij - Wyczyść historię - Dodaj - Zapisz - Udostępnij - Szukaj - Szukaj mang - Pobieranie… - Pobrano - Pobrane - Nazwa - Popularność - Najnowsze - Ocena - Filtry - Jasny - Ciemny - Strony - Wyczyść - Usuń - Udostępnij zdjęcie - Usuń - Brak opisu - Tryb czytania - Błąd sieci - Obliczanie… - Spróbuj ponownie - Nic nie znaleziono - Brak historii - Czytaj - Brak ulubionych - Dodaj do ulubionych - Nowa kategoria - Stwórz skrót… - Udostępnij %s - Przetwarzanie… - Zaktualizowane - Zapisz stronę - Zapisano - Wibracje - Biblioteka - Ostatnie - Tryb czarny - Przygotowywanie… - Plik nieznaleziony - Wczoraj - Dawno temu - Grupa - Dzisiaj - Zaloguj - Dalej - Potwierdź - Witaj - Skończone - W trakcie - Zezwól - Proponowane - Włącz propozycje - Włączone - Wyłączone - Nigdy - Zawsze - Znajdź rozdział - %1$s%% - Wygląd - Schowaj - Synchronizacja - Synchronizuj swoje dane - Nazwa - Edytuj - Wyloguj - Cofnij - Wyślij - Planowane - Czytane - Czytane ponownie - Skończone - Pokaż wszystkie - Wybierz zakres - Wyczyść całą historię - Ostatnie 2 godziny - Historia wyczyszczona - Zarządzaj - Losowe - Puste - Przeglądaj - Dostępne - Ustawienia - Źródło wyłączone - Kompaktowy - Błąd po stronie serwera (%1$d). Sprónuj ponownie później - Sieć niedostępna - Inne języki - Odrzuć - Jasność - Kontrast - Korekcja kolorów - Automatyczne przewijanie - Brak rozdziałów - Tryb incognito - Usunięto z ulubionych - Wykorzystana pamięć - Zapisane mangi - Brak zakładek - Możesz tworzyć zakładki w trakcie czytania mangi - Zakładki usunięte - Twoje ostatnio czytane mangi - Wyłącz wszystkie - Wyłącz optymalizację baterii - Autowykrywanie trybu czytania - Usunięte z historii - Dodano zakładkę - Usunięto zakładkę - Zakładki - Usuń zakładkę - Dodaj zakładkę - Brak ulubionych kategorii - Edytuj kategorię - Włącz powiadomienia - Wróć - Konto już istnieje - Anulowano - Zwolnienie pobierania - Brak rozdziałów w tej mandze - Różne języki - Tylko na Wi-Fi - Zawsze blokuj - Gatunki - Znajdź gatunek - Czytaj więcej - Rozwiąż - Wymagane CAPTCHA - Cichy - Dotknij aby spróbować ponownie - Teraz - Przywrócone - Dopasuj do szerokości - Dopasuj do wysokości - Dopasuj do środka - Nowa kategoria - Brak nowych aktualizacji - Sprawdź dostępność aktualizacji - Wersja %s - O aplikacji - Usuń - Jest tu dosyć pusto… - Ulubione kategorie - Powiadomienie LED - Nowe rozdziały - Pamięć wewnętrzna - Tutaj będą wyświetlane Twoje mangi - Znajdź materiały do czytania w zakładce „Przeglądaj” - W tym miejscu pojawią się powiadomienia o nowych rozdziałach z mang które czytasz - Strony w pamięci podręcznej - Animacja przewracania strony - Inne rzeczy w pamięci podręcznej - Otwórz w przeglądarce - Numerowane strony - Powiadomienia - Dźwięk powiadomień - Ustawienia powiadomień - Zewnętrzne źródła - Motyw - Systemowy - Historia i pamięć podręczna - Wyczyść pamięć podręczną stron - B|kB|MB|GB|TB - Wielkość siatki - Szukaj na %s - Usuń mangę - Dalej - Błąd - Wyczyszczone - Pamięć wewnętrzna - Pamięć zewnętrzna - Domena - Nowa wersja aplikacji jest dostępna - Ta manga ma %s. Zapisać wszystko? - Zapisz - Pobierz - Najpierw coś zapisz - Niedostępne - Zapisz - Wszystkie ulubione - Pusta kategoria - Czytaj później - Aktualizacje - Nowa wersja: %s - Wielkość: %s - Obróć ekran - Odśwież - Szukaj aktualizacji - Nie sprawdzaj - Wprowadź hasło - Złe hasło - Chroń aplikację - Pytaj o hasło przy starcie Kotatsu - Wprowadź ponownie hasło - Zużywa mniej prądu na ekranach AMOLED - Kopia zapasowa i przywracanie - Utwórz kopię zapasową danych - Przywróć z kopii zapasowej - 18+ - %1$d na %2$d włączone - Standardowy - Webtoon - Ustawienia czytnika - Zmiana strony - Przyciski głośności - Dotknięcie krawędzi - Wyczyszczone - Tryb skalowania - Wyczyść ciasteczka - Wszystkie ciasteczka wyczyszczone - Przetłumacz tą aplikację - Tłumaczenie - Dostępne źródła - Tylko gesty - Brak dostępnej pamięci - Inny - Wyniki wyszukiwania - Wszystkie dane zostały przywrócone - Dane zostały przywrócone, ale z błędami - Od tyłu - Domyślny - Polityka zrzutów ekranu - Wyklucz gatunki - Określ gatunki, których nie chcesz widzieć w sugestiach - Zalogowano jako %s - Wybierz języki, w których chcesz czytać mangi. Możesz zmienić to później w ustawieniach. - Zgłoś - Usuwanie danych - Nieważna domena - Zmień kolejność - Potwierdzenie wyjścia - %s - %s - Rozdz. %1$d/%2$d Str. %3$d/%4$d - Włącz Wi-Fi lub sieć komórkową, aby czytać mangę online - Importuj - Wybierz plik ZIP lub CBZ. - Wyczyść historię wyszukiwania - Ta operacja nie jest obsługiwana - Tryb sortowania - Treści - Nie można załadować listy gatunków - Wstrzymane - Porzucone - Użyj odcisku palca, jeśli jest dostępny - Mangi z Twoich ulubionych - Pokaż wskaźniki postępu czytania - Pokaż procent przeczytania w historii i ulubionych - Manga oznaczona jako NSFW nigdy nie zostanie dodana do historii, a Twoje postępy nie zostaną zapisane - DNS przez HTTPS - Tryb domyślny - Trwale wyczyścić całą historię czytania? - „%s” usunięte z pamięci lokalnej - Wyczyść tablicę aktualizacji - Tablica - Usunąć trwale „%s” z urządzenia? - Wyczyść pamięć podręczną miniatur - Spróbuj przeformułować zapytanie. - To co czytasz będzie wyświetlane tutaj - Znajdź to, co warto przeczytać, w menu bocznym. - Zapisz ze źródeł online lub zaimportuj pliki. - Folder pobranych - Aktualizacja tablicy rozpocznie się wkrótce - Niezgodne hasła - Od prawej do lewej - Trzymaj na starcie - Możesz utworzyć kopię zapasową swojej historii i ulubionych oraz przywrócić ją - Wybrana konfiguracja zostanie zapamiętana dla tej mangi - Wyczyść tablicę - Wyczyścić trwale całą historię aktualizacji? - Szukanie nowych rozdziałów - Zaloguj się, aby wyświetlić tę zawartość - Domyślnie: %s - Wprowadź hasło, aby uruchomić aplikację - Hasło musi mieć co najmniej 4 znaki - Trwale usunąć wszystkie ostatnie zapytania wyszukiwania? - Zapisano kopię zapasową - Systemy niektórych urządzeń inaczej się zachowują. Może to zakłócać wykonywanie zadań w tle. - W kolejce - Pobierz lub przeczytaj ten brakujący rozdział online. - Brak rozdziału - Uprawniony - Logowanie na %s nie jest obsługiwane - Zostaniesz wylogowany ze wszystkich źródeł - Wyklucz mangi NSFW z historii - Wykorzystane źródła - Zablokuj na NSFW - Proponuj mangi na podstawie Twoich preferencji - Wszystkie dane są analizowane tylko lokalnie na tym urządzeniu i nigdy nie są nigdzie wysyłane. - Zacznij czytać mangę, a otrzymasz spersonalizowane sugestie - Nie proponuj mang NSFW - Zresetuj filtr - Ładuj wstępnie strony - Aktualizowanie sugestii - Trwale usunąć wybrane elementy z urządzenia? - Usuwanie zakończone - Pomaga uniknąć blokowania Twojego adresu IP - Przetwarzanie zapisanej mangi - Rozdziały zostaną usunięte w tle - Wpisz swój adres e-mail, aby kontynuować - Dostępne są nowe źródła mang - Sprawdzaj dostępność nowych rozdziałów i informuj o nich - Będziesz otrzymywać powiadomienia o aktualizacjach mang, które czytasz - Nie będziesz otrzymywać powiadomień, ale nowe rozdziały będą podświetlane na listach - Śledzenie - Automatycznie wykryj, czy manga to webtoon - Pomaga w sprawdzaniu aktualizacji w tle - Coś poszło nie tak. Zgłoś błąd programistom, aby pomóc nam go naprawić. - Może pomóc w przypadku niektórych problemów. Wszystkie autoryzacje zostaną unieważnione - Brak źródeł mang - Włącz źródła mang do czytania mang online - Czy na pewno chcesz usunąć wybrane ulubione kategorie\? + Ulubione + Historia + Napotkano błąd + Szczegółowy + Rozdziały + Lista + Lista szczegółowa + Siatka + Tryb listy + Ustawienia + Ładowanie… + Rozdział %1$d z %2$d + Zamknij + Wyczyść historię + Dodaj + Zapisz + Udostępnij + Szukaj + Szukaj mang + Pobieranie… + Pobrano + Pobrane + Nazwa + Popularność + Najnowsze + Ocena + Filtry + Jasny + Ciemny + Strony + Wyczyść + Usuń + Udostępnij zdjęcie + Usuń + Brak opisu + Tryb czytania + Błąd sieci + Obliczanie… + Spróbuj ponownie + Nic nie znaleziono + Brak historii + Czytaj + Brak ulubionych + Dodaj do ulubionych + Nowa kategoria + Stwórz skrót… + Udostępnij %s + Przetwarzanie… + Zaktualizowane + Zapisz stronę + Zapisano + Wibracje + Biblioteka + Ostatnie + Tryb czarny + Przygotowywanie… + Plik nieznaleziony + Wczoraj + Dawno temu + Grupa + Dzisiaj + Zaloguj + Dalej + Potwierdź + Witaj + Skończone + W trakcie + Zezwól + Proponowane + Włącz propozycje + Włączone + Wyłączone + Nigdy + Zawsze + Znajdź rozdział + %1$s%% + Wygląd + Schowaj + Synchronizacja + Synchronizuj swoje dane + Nazwa + Edytuj + Wyloguj + Cofnij + Wyślij + Planowane + Czytane + Czytane ponownie + Skończone + Pokaż wszystkie + Wybierz zakres + Wyczyść całą historię + Ostatnie 2 godziny + Historia wyczyszczona + Zarządzaj + Losowe + Puste + Przeglądaj + Dostępne + Ustawienia + Źródło wyłączone + Kompaktowy + Błąd po stronie serwera (%1$d). Sprónuj ponownie później + Sieć niedostępna + Inne języki + Odrzuć + Jasność + Kontrast + Korekcja kolorów + Automatyczne przewijanie + Brak rozdziałów + Tryb incognito + Usunięto z ulubionych + Wykorzystana pamięć + Zapisane mangi + Brak zakładek + Możesz tworzyć zakładki w trakcie czytania mangi + Zakładki usunięte + Twoje ostatnio czytane mangi + Wyłącz wszystkie + Wyłącz optymalizację baterii + Autowykrywanie trybu czytania + Usunięte z historii + Dodano zakładkę + Usunięto zakładkę + Zakładki + Usuń zakładkę + Dodaj zakładkę + Brak ulubionych kategorii + Edytuj kategorię + Włącz powiadomienia + Wróć + Konto już istnieje + Anulowano + Zwolnienie pobierania + Brak rozdziałów w tej mandze + Różne języki + Tylko na Wi-Fi + Zawsze blokuj + Gatunki + Czytaj więcej + Rozwiąż + Wymagane CAPTCHA + Cichy + Dotknij aby spróbować ponownie + Teraz + Przywrócone + Dopasuj do szerokości + Dopasuj do wysokości + Dopasuj do środka + Nowa kategoria + Brak nowych aktualizacji + Sprawdź dostępność aktualizacji + Wersja %s + O aplikacji + Usuń + Jest tu dosyć pusto… + Ulubione kategorie + Powiadomienie LED + Nowe rozdziały + Pamięć wewnętrzna + Tutaj będą wyświetlane Twoje mangi + Znajdź materiały do czytania w zakładce „Przeglądaj” + W tym miejscu pojawią się powiadomienia o nowych rozdziałach z mang które czytasz + Strony w pamięci podręcznej + Animacja przewracania strony + Inne rzeczy w pamięci podręcznej + Otwórz w przeglądarce + Numerowane strony + Powiadomienia + Dźwięk powiadomień + Ustawienia powiadomień + Zewnętrzne źródła + Motyw + Systemowy + Wyczyść pamięć podręczną stron + B|kB|MB|GB|TB + Wielkość siatki + Szukaj na %s + Usuń mangę + Dalej + Błąd + Wyczyszczone + Pamięć wewnętrzna + Pamięć zewnętrzna + Domena + Nowa wersja aplikacji jest dostępna + Ta manga ma %s. Zapisać wszystko? + Zapisz + Pobierz + Najpierw coś zapisz + Niedostępne + Zapisz + Wszystkie ulubione + Pusta kategoria + Czytaj później + Aktualizacje + Nowa wersja: %s + Wielkość: %s + Obróć ekran + Odśwież + Szukaj aktualizacji + Nie sprawdzaj + Wprowadź hasło + Złe hasło + Chroń aplikację + Pytaj o hasło przy starcie Kotatsu + Wprowadź ponownie hasło + Zużywa mniej prądu na ekranach AMOLED + Kopia zapasowa i przywracanie + Utwórz kopię zapasową danych + Przywróć z kopii zapasowej + 18+ + %1$d na %2$d włączone + Standardowy + Webtoon + Ustawienia czytnika + Zmiana strony + Przyciski głośności + Dotknięcie krawędzi + Wyczyszczone + Tryb skalowania + Wyczyść ciasteczka + Wszystkie ciasteczka wyczyszczone + Przetłumacz tą aplikację + Tłumaczenie + Dostępne źródła + Tylko gesty + Brak dostępnej pamięci + Inny + Wyniki wyszukiwania + Wszystkie dane zostały przywrócone + Dane zostały przywrócone, ale z błędami + Od tyłu + Domyślny + Polityka zrzutów ekranu + Wyklucz gatunki + Określ gatunki, których nie chcesz widzieć w sugestiach + Zalogowano jako %s + Wybierz języki, w których chcesz czytać mangi. Możesz zmienić to później w ustawieniach. + Zgłoś + Usuwanie danych + Nieważna domena + Zmień kolejność + Potwierdzenie wyjścia + %s - %s + Rozdz. %1$d/%2$d Str. %3$d/%4$d + Włącz Wi-Fi lub sieć komórkową, aby czytać mangę online + Importuj + Wybierz plik ZIP lub CBZ. + Wyczyść historię wyszukiwania + Ta operacja nie jest obsługiwana + Tryb sortowania + Nie można załadować listy gatunków + Wstrzymane + Porzucone + Użyj odcisku palca, jeśli jest dostępny + Mangi z Twoich ulubionych + Pokaż wskaźniki postępu czytania + Pokaż procent przeczytania w historii i ulubionych + Manga oznaczona jako NSFW nigdy nie zostanie dodana do historii, a Twoje postępy nie zostaną zapisane + DNS przez HTTPS + Tryb domyślny + Trwale wyczyścić całą historię czytania? + „%s” usunięte z pamięci lokalnej + Wyczyść tablicę aktualizacji + Tablica + Usunąć trwale „%s” z urządzenia? + Wyczyść pamięć podręczną miniatur + Spróbuj przeformułować zapytanie. + To co czytasz będzie wyświetlane tutaj + Znajdź to, co warto przeczytać, w menu bocznym. + Zapisz ze źródeł online lub zaimportuj pliki. + Folder pobranych + Aktualizacja tablicy rozpocznie się wkrótce + Niezgodne hasła + Od prawej do lewej + Trzymaj na starcie + Możesz utworzyć kopię zapasową swojej historii i ulubionych oraz przywrócić ją + Wybrana konfiguracja zostanie zapamiętana dla tej mangi + Wyczyść tablicę + Wyczyścić trwale całą historię aktualizacji? + Szukanie nowych rozdziałów + Zaloguj się, aby wyświetlić tę zawartość + Domyślnie: %s + Wprowadź hasło, aby uruchomić aplikację + Hasło musi mieć co najmniej 4 znaki + Trwale usunąć wszystkie ostatnie zapytania wyszukiwania? + Zapisano kopię zapasową + Systemy niektórych urządzeń inaczej się zachowują. Może to zakłócać wykonywanie zadań w tle. + W kolejce + Brak rozdziału + Uprawniony + Logowanie na %s nie jest obsługiwane + Zostaniesz wylogowany ze wszystkich źródeł + Wyklucz mangi NSFW z historii + Wykorzystane źródła + Zablokuj na NSFW + Proponuj mangi na podstawie Twoich preferencji + Wszystkie dane są analizowane tylko lokalnie na tym urządzeniu i nigdy nie są nigdzie wysyłane. + Zacznij czytać mangę, a otrzymasz spersonalizowane sugestie + Nie proponuj mang NSFW + Zresetuj filtr + Ładuj wstępnie strony + Aktualizowanie sugestii + Trwale usunąć wybrane elementy z urządzenia? + Usuwanie zakończone + Pomaga uniknąć blokowania Twojego adresu IP + Przetwarzanie zapisanej mangi + Rozdziały zostaną usunięte w tle + Wpisz swój adres e-mail, aby kontynuować + Dostępne są nowe źródła mang + Sprawdzaj dostępność nowych rozdziałów i informuj o nich + Będziesz otrzymywać powiadomienia o aktualizacjach mang, które czytasz + Nie będziesz otrzymywać powiadomień, ale nowe rozdziały będą podświetlane na listach + Śledzenie + Automatycznie wykryj, czy manga to webtoon + Pomaga w sprawdzaniu aktualizacji w tle + Coś poszło nie tak. Zgłoś błąd programistom, aby pomóc nam go naprawić. + Może pomóc w przypadku niektórych problemów. Wszystkie autoryzacje zostaną unieważnione + Brak źródeł mang + Włącz źródła mang do czytania mang online + Czy na pewno chcesz usunąć wybrane ulubione kategorie\? \nWszystkie w nich mangi zostaną usunięte i nie będzie można tego cofnąć. - Naciśnij ponownie Wstecz, aby wyjść - Naciśnij dwukrotnie przycisk Wstecz, aby wyjść z aplikacji - Treść nie została znaleziona lub została usunięta - Pokaż pasek informacji w czytniku - Archiwum komiksów - Folder z obrazami - Importowanie mangi - Importowanie zakończone - Możesz usunąć oryginalny plik z pamięci, aby zaoszczędzić miejsce - Import rozpocznie się wkrótce - Wybrane ustawienia kolorów zostaną zapamiętane dla tej mangi - Pokaż ostatnie skróty do mang - Pokaż ostatnie mangi po długim naciśnięciu ikony aplikacji - Stuknięcie w prawą krawędź lub naciśnięcie prawego klawisza zawsze powoduje przejście do następnej strony - Ergonomiczne sterowanie czytnikiem - Zapisać czy odrzucić niezapisane zmiany? - Brak miejsca w urządzeniu - Pokaż suwak przełączania stron - Powiększanie webtoon - Wyczyść też informacje o nowych rozdziałach - Resetuj - Szczegóły błędu:<br><tt>%1$s</tt><br><br>1. Spróbuj <a href=%2$s>otworzyć mangę w przeglądarce internetowej</a>, aby upewnić się, że jest dostępna w swoim źródle<br>2. Upewnij się, że używasz <a href=kotatsu://about>najnowszej wersji Kotatsu</a><br>3. Jeśli jest dostępny, wyślij raport o błędzie do programistów. - Mamimi - Kanade - Usługi - Tutaj nic nie ma - By śledzić postęp w czytaniu, wybierz Menu → Śledź na ekranie detali mangi. - Znajdź podobne - Nagłówek UserAgent - Tłumaczenia - Udostępnij dzienniki - Zapisz niektóre działania do celów debugowania - Zezwól na niestabilne altualizacje - Rozumiem - Uruchom ponownie aplikację by wprowadzić te zmiany - Prędkość - Stuknij i przytrzymaj element, aby zmienić jego kolejność - Możesz wybrać jeden lub więcej plików .cbz lub .zip, każdy plik zostanie rozpoznany jako osobna manga. - Możesz wybrać katalog z archiwami lub obrazami. Każde archiwum (lub podkatalog) zostanie rozpoznane jako rozdział. - Włączać - Wstępne ładowanie treści - Oznacz jako aktualne - Włącz logowanie - Pokaż podejrzane treści - Schemat kolorów - Pokaż w widoku siatki - Miku - Dynamiczne - Asuka - Rikka - Sakura - Mion - Ignoruj błędy SSL - Wybierz lustro automatycznie - Zaimportuj utworzoną wcześniej kopię zapasową danych użytkownika - Pokaż na półce - Automatycznie przełączaj domeny dla zdalnych źródeł w przypadku błędów, jeśli dostępne są kopie lustrzane - Pauza - Wznawiać - Wstrzymane - Anulować całość - Pobieraj tylko przez Wi-Fi - Zatrzymaj pobieranie po przełączeniu na sieć komórkową - Sugestia: %s - Czasami wyświetlaj powiadomienia z sugerowaną mangą - Więcej - Nie, dziękuję - Wszystkie aktywne pobrania zostaną anulowane, częściowo pobrane dane zostaną utracone - Usuwanie zakończone - Język - Zaproponuj aktualizacje do wersji beta aplikacji - Pobieranie rozpoczęte - Ustawienia synchronizacji - Adres serwera - Możesz użyć samoobsługowego serwera synchronizacji lub serwera domyślnego. Nie zmieniaj tego, jeśli nie jesteś pewien, co robisz. - Twoja historia pobrań zostanie trwale usunięta - Nie masz żadnych pobrań - Pobieranie zostało wstrzymane - Pobieranie zostało wznowione - Pobieranie zostało anulowane - Pliki do pobrania zostały usunięte - Czy chcesz otrzymywać spersonalizowane sugestie dotyczące mangi\? - WebView niedostępny: sprawdź, czy dostawca WebView jest zainstalowany - Wyczyść pamięć podręczną sieci - Typ - Adres - Port - Proxy - Możesz zalogować się na istniejące konto lub utworzyć nowe - \ No newline at end of file + Naciśnij ponownie Wstecz, aby wyjść + Naciśnij dwukrotnie przycisk Wstecz, aby wyjść z aplikacji + Treść nie została znaleziona lub została usunięta + Pokaż pasek informacji w czytniku + Archiwum komiksów + Folder z obrazami + Importowanie mangi + Importowanie zakończone + Możesz usunąć oryginalny plik z pamięci, aby zaoszczędzić miejsce + Import rozpocznie się wkrótce + Wybrane ustawienia kolorów zostaną zapamiętane dla tej mangi + Pokaż ostatnie skróty do mang + Pokaż ostatnie mangi po długim naciśnięciu ikony aplikacji + Stuknięcie w prawą krawędź lub naciśnięcie prawego klawisza zawsze powoduje przejście do następnej strony + Ergonomiczne sterowanie czytnikiem + Zapisać czy odrzucić niezapisane zmiany? + Brak miejsca w urządzeniu + Pokaż suwak przełączania stron + Powiększanie webtoon + Wyczyść też informacje o nowych rozdziałach + Resetuj + Szczegóły błędu:<br><tt>%1$s</tt><br><br>1. Spróbuj <a href=%2$s>otworzyć mangę w przeglądarce internetowej</a>, aby upewnić się, że jest dostępna w swoim źródle<br>2. Upewnij się, że używasz <a href=kotatsu://about>najnowszej wersji Kotatsu</a><br>3. Jeśli jest dostępny, wyślij raport o błędzie do programistów. + Mamimi + Kanade + Usługi + Tutaj nic nie ma + By śledzić postęp w czytaniu, wybierz Menu → Śledź na ekranie detali mangi. + Znajdź podobne + Nagłówek UserAgent + Tłumaczenia + Udostępnij dzienniki + Zapisz niektóre działania do celów debugowania + Zezwól na niestabilne altualizacje + Rozumiem + Uruchom ponownie aplikację by wprowadzić te zmiany + Prędkość + Stuknij i przytrzymaj element, aby zmienić jego kolejność + Możesz wybrać jeden lub więcej plików .cbz lub .zip, każdy plik zostanie rozpoznany jako osobna manga. + Możesz wybrać katalog z archiwami lub obrazami. Każde archiwum (lub podkatalog) zostanie rozpoznane jako rozdział. + Włączać + Wstępne ładowanie treści + Oznacz jako aktualne + Włącz logowanie + Pokaż podejrzane treści + Schemat kolorów + Pokaż w widoku siatki + Miku + Dynamiczne + Asuka + Rikka + Sakura + Mion + Ignoruj błędy SSL + Wybierz lustro automatycznie + Zaimportuj utworzoną wcześniej kopię zapasową danych użytkownika + Pokaż na półce + Automatycznie przełączaj domeny dla zdalnych źródeł w przypadku błędów, jeśli dostępne są kopie lustrzane + Pauza + Wznawiać + Wstrzymane + Anulować całość + Pobieraj tylko przez Wi-Fi + Zatrzymaj pobieranie po przełączeniu na sieć komórkową + Sugestia: %s + Czasami wyświetlaj powiadomienia z sugerowaną mangą + Więcej + Nie, dziękuję + Wszystkie aktywne pobrania zostaną anulowane, częściowo pobrane dane zostaną utracone + Usuwanie zakończone + Język + Zaproponuj aktualizacje do wersji beta aplikacji + Pobieranie rozpoczęte + Ustawienia synchronizacji + Adres serwera + Możesz użyć samoobsługowego serwera synchronizacji lub serwera domyślnego. Nie zmieniaj tego, jeśli nie jesteś pewien, co robisz. + Twoja historia pobrań zostanie trwale usunięta + Nie masz żadnych pobrań + Pobieranie zostało wstrzymane + Pobieranie zostało wznowione + Pobieranie zostało anulowane + Pliki do pobrania zostały usunięte + Czy chcesz otrzymywać spersonalizowane sugestie dotyczące mangi\? + WebView niedostępny: sprawdź, czy dostawca WebView jest zainstalowany + Wyczyść pamięć podręczną sieci + Typ + Adres + Port + Proxy + Możesz zalogować się na istniejące konto lub utworzyć nowe + diff --git a/app/src/main/res/values-pt-rBR/plurals.xml b/app/src/main/res/values-pt-rBR/plurals.xml index ff7cb185c..081afb690 100644 --- a/app/src/main/res/values-pt-rBR/plurals.xml +++ b/app/src/main/res/values-pt-rBR/plurals.xml @@ -8,10 +8,6 @@ %1$d capítulo %1$d capítulos - - Total de %1$d página - Total de %1$d páginas - %1$d novo capítulo %1$d novos capítulos diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 41f1dc1a9..b52effbd3 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -56,7 +56,6 @@ Deletar Escolha um arquivo ZIP ou CBZ. Sem descrição - Histórico e cache Limpar cache da página B|kB|MB|GB|TB Padrão @@ -150,7 +149,6 @@ Alguns dispositivos têm um comportamento de sistema diferente, o que pode interromper as tarefas em segundo plano. Consulte mais informação Na fila - Baixe ou leia este capítulo perdido online. O capítulo está em falta Traduzir este aplicativo Tradução @@ -180,7 +178,6 @@ Desabilitado Não foi possível carregar a lista de gêneros Redefinir filtro - Encontrar gênero Selecione os idiomas que você deseja ler mangá. Você pode alterá-lo mais tarde nas configurações. Nunca Somente em Wi-Fi @@ -226,7 +223,6 @@ %1$s%% Atualização de sugestões Aparência - Conteúdo Excluir gêneros Especifique os gêneros que você não deseja ver nas sugestões Remoção concluída diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index eae27e6af..eaefda767 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -47,7 +47,6 @@ Atualizado Deletar Essa operação não é suportada - Histórico e cache Limpar cache de página B|kB|MB|GB|TB Padrão @@ -156,7 +155,6 @@ Fontes usadas Enfileirado Traduzir esta aplicação - Baixe ou leia este capítulo perdido online. O capítulo está em falta Autorizado O login em %s não é suportado @@ -213,7 +211,6 @@ Não foi possível carregar a lista de gêneros Somente em Wi-Fi Selecione os idiomas que deseja ler mangá. Pode alterá-lo mais tarde nas configurações. - Encontrar gênero Sempre Redefinir filtro Nunca @@ -224,7 +221,6 @@ Atualização das sugestões Aparência Encontrar capítulo - Conteúdo Não há capítulos nesta manga %1$s%% O seu mangá será exibido aqui diff --git a/app/src/main/res/values-ru/plurals.xml b/app/src/main/res/values-ru/plurals.xml index 9dcd4db39..a3ef775fa 100644 --- a/app/src/main/res/values-ru/plurals.xml +++ b/app/src/main/res/values-ru/plurals.xml @@ -1,10 +1,5 @@ - - Всего %1$d страница - Всего %1$d страницы - Всего %1$d страниц - %1$d элемент %1$d элемента diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index ff3015e29..8484a01fc 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1,422 +1,418 @@ - На устройстве - Избранное - История - Произошла ошибка - Ошибка сети - Подробности - Главы - Список - Подробный список - Сетка - Вид списка - Настройки - Источники манги - Загрузка… - Глава %1$d из %2$d - Закрыть - Повторить - Очистить историю - Ничего не найдено - Истории пока нет - Читать - Избранного пока нет - В избранное - Новая категория - Добавить - Сохранить - Поделиться - Создать ярлык… - Поделиться %s - Поиск - Поиск манги - Загрузка… - Обработка… - Загружено - Загрузки - Имя - Популярная - Обновлённая - Новая - Рейтинг - Порядок сортировки - Фильтр - Тема - Светлая - Тёмная - Как в системе - Страницы - Очистить - Очистить всю историю чтения полностью\? - Удалить - «%s» удалено с устройства - Сохранить страницу - Сохранено - Поделиться изображением - Импорт - Удалить - Операция не поддерживается - Выберите файл в формате CBZ или ZIP. - Описание отсутствует - История и кэш - Очистить кэш страниц - Б|кБ|МБ|ГБ|ТБ - Стандартный - Манхва - Режим чтения - Размер сетки - Поиск по %s - Удалить мангу - Удалить \"%s\" с устройства навсегда\? - Настройки режима чтения - Листание страниц - Нажатия по краям - Кнопки громкости - Продолжить - Ошибка - Очистить кэш миниатюр - Очистить историю поиска - Очищено - Только жесты - Внутренний накопитель - Внешний накопитель - Домен - Доступна новая версия приложения - Открыть в веб-браузере - В этой манге %s. Сохранить их все\? - Сохранить - Уведомления - Включено %1$d из %2$d - Новые главы - Загрузить - Настройки уведомлений - Звук уведомления - Светодиодная индикация - Вибросигнал - Категории избранного - Удалить - Как-то здесь пусто… - Попробуйте переформулировать запрос. - То, что вы прочитаете, будет отображено здесь - Найдите, что почитать, в боковом меню. - Сохраните что-нибудь - Сохраните что-нибудь из онлайн-каталога или импортируйте из файла. - Полка - Недавнее - Анимация пролистывания - Папка для загрузок - Недоступно - Нет доступного хранилища - Другое хранилище - Готово - Всё избранное - Категория пуста - Прочитать позже - Обновления - Новые главы из того, что вы читаете, будут показаны здесь - Результаты поиска - Новая версия: %s - Размер: %s - Очистить ленту обновлений - Очищено - Повернуть экран - Обновить - Обновление скоро начнётся - Следить за обновлениями - Не проверять - Введите пароль - Неверный пароль - Защитить приложение - Запрашивать пароль при запуске Kotatsu - Повторите пароль - Пароли не совпадают - О программе - Версия %s - Проверить обновления - Нет доступных обновлений - Справа налево - Создать категорию - Масштабирование - Вписать в экран - Подогнать по высоте - Подогнать по ширине - Исходный размер - Чёрная - Потребляет меньше энергии на экранах AMOLED - Резервное копирование и восстановление - Создать резервную копию - Восстановить данные - Восстановлено - Подготовка… - Файл не найден - Все данные были восстановлены - Данные были восстановлены, но возникли некоторые ошибки - Вы можете создать резервную копию избранного и истории и потом восстановить их - Только что - Вчера - Давно - Группировать - Сегодня - Попробовать ещё раз - Выбранный режим будет сохранён для текущей манги - Без звука - Необходимо пройти CAPTCHA - Пройти - Очистить куки - Все файлы cookie были удалены - Очистить ленту - Удалить всю историю обновлений навсегда\? - Проверка новых глав - В обратном порядке - Войти - Авторизуйтесь, чтобы просмотреть этот контент - По умолчанию: %s - Далее - Введите пароль для запуска приложения - Подтвердить - Пароль должен состоять из 4 символов или более - Добро пожаловать - Удалить все последние поисковые запросы навсегда\? - Резервная копия сохранена - Некоторые устройства имеют различное поведение системы, что может привести к нарушению фоновых задач. - Подробнее - В очереди - Глава отсутствует - Скачайте или прочитайте эту недостающую главу онлайн. - Помочь с переводом приложения - Перевод - Авторизация выполнена - Вход в %s не поддерживается - Вы выйдете из всех источников - Жанры - Завершено - Онгоинг - По умолчанию - Исключить NSFW мангу из истории - Нумерация страниц - Включенные источники - Доступные источники - Политика скриншотов - Разрешить - Запретить для NSFW - Всегда блокировать - Рекомендации - Включить рекомендации - Предлагать мангу на основе Ваших предпочтений - Все данные анализируются только локально на этом устройстве и никуда не отправляются. - Начните читать мангу, чтобы получать персональные предложения - Не предлагать NSFW мангу - Включено - Выключено - Не удалось загрузить список жанров - Вычисление… - Сбросить фильтр - Поиск по жанрам - Выберите языки, на которых Вы хотите читать мангу. Это можно будет изменить позже в настройках. - Никогда - Только по Wi-Fi - Всегда - Предварительная загрузка страниц - Вы авторизованы как %s - 18+ - Разные языки - Найти главу - В этой манге нет глав - Оформление - Контент - Обновление рекомендаций - Исключить жанры - Укажите жанры, которые Вы не хотите видеть в рекомендациях - Удалить выбранную мангу с накопителя? - Удаление завершено - Замедление загрузки - Помогает избежать блокировки IP-адреса - Обработка сохранённой манги - Главы будут удалены в фоновом режиме - Скрыть - Доступны новые источники манги - Проверять новые главы и уведомлять о них - Вы будете получать уведомления об обновлении манги, которую Вы читаете - Вы не будете получать уведомления, но новые главы будут отображаться в списке - Включить уведомления - Название - Изменить - Изменить категорию - Отслеживание - Нет категорий избранного - Добавить закладку - Удалить закладку - Закладки - Закладка удалена - Закладка добавлена - Отменить - Удалено из истории - DNS поверх HTTPS - Режим по умолчанию - Автоопределение режима чтения - Автоматически определяет, является ли манга веб-комиксом - Отключить оптимизацию батареи - Помогает с фоновой проверкой обновлений - Что-то пошло не так. Пожалуйста, отправьте отчёт разработчикам, чтобы помочь всё исправить. - Отправить - Отключить все - Использовать отпечаток пальца, если доступно - Манга из Вашего избранного - Манга, которую Вы недавно читали - Читаю - Запланировано - Отложено - Заброшено - Завершено - Показать процент прочитанного в истории и избранном - Манга, помеченная как NSFW, никогда не будет добавлена в историю и ваш прогресс чтения не будет сохранен - %1$s%% - Отчёт - Выйти - Перечитываю - Показать индикаторы прогресса чтения - Удаление данных - Может помочь в случае каких-либо проблем. Все авторизации будут аннулированы - Показать все - Неверное доменное имя - Найдите, что почитать во разделе «Обзор» - Назад - Выбрать диапазон - История очищена - Настроить - Закладок пока нет - Закладки удалены - Нет источников манги - Включите источники манги для чтения онлайн - Случайная - Упорядочить - Пусто - Обзор - Нажмите Назад ещё раз, чтобы выйти - Нажмите Назад 2 раза для выхода из приложения - Другой кэш - Опции - Контент не найден или был удален - Гл. %1$d/%2$d Стр. %3$d/%4$d - Показывать информационную панель в режиме чтения - Архив комиксов - Вы можете удалить исходный файл из хранилища, чтобы сэкономить место на нём - Режим инкогнито - Синхронизация - Синхронизируйте ваши данные - Введите электронную почту, чтобы продолжить - Ваша манга будет показана здесь - Аккаунт уже существует - Вы можете создавать закладки во время чтения манги - Подтверждение выхода - Отменено - Очистить всю историю - Последние 2 часа - Вы уверены, что хотите удалить выбранные категории избранного\? + На устройстве + Избранное + История + Произошла ошибка + Ошибка сети + Подробности + Главы + Список + Подробный список + Сетка + Вид списка + Настройки + Источники манги + Загрузка… + Глава %1$d из %2$d + Закрыть + Повторить + Очистить историю + Ничего не найдено + Истории пока нет + Читать + Избранного пока нет + В избранное + Новая категория + Добавить + Сохранить + Поделиться + Создать ярлык… + Поделиться %s + Поиск + Поиск манги + Загрузка… + Обработка… + Загружено + Загрузки + Имя + Популярная + Обновлённая + Новая + Рейтинг + Порядок сортировки + Фильтр + Тема + Светлая + Тёмная + Как в системе + Страницы + Очистить + Очистить всю историю чтения полностью\? + Удалить + «%s» удалено с устройства + Сохранить страницу + Сохранено + Поделиться изображением + Импорт + Удалить + Операция не поддерживается + Выберите файл в формате CBZ или ZIP. + Описание отсутствует + Очистить кэш страниц + Б|кБ|МБ|ГБ|ТБ + Стандартный + Манхва + Режим чтения + Размер сетки + Поиск по %s + Удалить мангу + Удалить \"%s\" с устройства навсегда\? + Настройки режима чтения + Листание страниц + Нажатия по краям + Кнопки громкости + Продолжить + Ошибка + Очистить кэш миниатюр + Очистить историю поиска + Очищено + Только жесты + Внутренний накопитель + Внешний накопитель + Домен + Доступна новая версия приложения + Открыть в веб-браузере + В этой манге %s. Сохранить их все\? + Сохранить + Уведомления + Включено %1$d из %2$d + Новые главы + Загрузить + Настройки уведомлений + Звук уведомления + Светодиодная индикация + Вибросигнал + Категории избранного + Удалить + Как-то здесь пусто… + Попробуйте переформулировать запрос. + То, что вы прочитаете, будет отображено здесь + Найдите, что почитать, в боковом меню. + Сохраните что-нибудь + Сохраните что-нибудь из онлайн-каталога или импортируйте из файла. + Полка + Недавнее + Анимация пролистывания + Папка для загрузок + Недоступно + Нет доступного хранилища + Другое хранилище + Готово + Всё избранное + Категория пуста + Прочитать позже + Обновления + Новые главы из того, что вы читаете, будут показаны здесь + Результаты поиска + Новая версия: %s + Размер: %s + Очистить ленту обновлений + Очищено + Повернуть экран + Обновить + Обновление скоро начнётся + Следить за обновлениями + Не проверять + Введите пароль + Неверный пароль + Защитить приложение + Запрашивать пароль при запуске Kotatsu + Повторите пароль + Пароли не совпадают + О программе + Версия %s + Проверить обновления + Нет доступных обновлений + Справа налево + Создать категорию + Масштабирование + Вписать в экран + Подогнать по высоте + Подогнать по ширине + Исходный размер + Чёрная + Потребляет меньше энергии на экранах AMOLED + Резервное копирование и восстановление + Создать резервную копию + Восстановить данные + Восстановлено + Подготовка… + Файл не найден + Все данные были восстановлены + Данные были восстановлены, но возникли некоторые ошибки + Вы можете создать резервную копию избранного и истории и потом восстановить их + Только что + Вчера + Давно + Группировать + Сегодня + Попробовать ещё раз + Выбранный режим будет сохранён для текущей манги + Без звука + Необходимо пройти CAPTCHA + Пройти + Очистить куки + Все файлы cookie были удалены + Очистить ленту + Удалить всю историю обновлений навсегда\? + Проверка новых глав + В обратном порядке + Войти + Авторизуйтесь, чтобы просмотреть этот контент + По умолчанию: %s + Далее + Введите пароль для запуска приложения + Подтвердить + Пароль должен состоять из 4 символов или более + Добро пожаловать + Удалить все последние поисковые запросы навсегда\? + Резервная копия сохранена + Некоторые устройства имеют различное поведение системы, что может привести к нарушению фоновых задач. + Подробнее + В очереди + Глава отсутствует + Помочь с переводом приложения + Перевод + Авторизация выполнена + Вход в %s не поддерживается + Вы выйдете из всех источников + Жанры + Завершено + Онгоинг + По умолчанию + Исключить NSFW мангу из истории + Нумерация страниц + Включенные источники + Доступные источники + Политика скриншотов + Разрешить + Запретить для NSFW + Всегда блокировать + Рекомендации + Включить рекомендации + Предлагать мангу на основе Ваших предпочтений + Все данные анализируются только локально на этом устройстве и никуда не отправляются. + Начните читать мангу, чтобы получать персональные предложения + Не предлагать NSFW мангу + Включено + Выключено + Не удалось загрузить список жанров + Вычисление… + Сбросить фильтр + Выберите языки, на которых Вы хотите читать мангу. Это можно будет изменить позже в настройках. + Никогда + Только по Wi-Fi + Всегда + Предварительная загрузка страниц + Вы авторизованы как %s + 18+ + Разные языки + Найти главу + В этой манге нет глав + Оформление + Обновление рекомендаций + Исключить жанры + Укажите жанры, которые Вы не хотите видеть в рекомендациях + Удалить выбранную мангу с накопителя? + Удаление завершено + Замедление загрузки + Помогает избежать блокировки IP-адреса + Обработка сохранённой манги + Главы будут удалены в фоновом режиме + Скрыть + Доступны новые источники манги + Проверять новые главы и уведомлять о них + Вы будете получать уведомления об обновлении манги, которую Вы читаете + Вы не будете получать уведомления, но новые главы будут отображаться в списке + Включить уведомления + Название + Изменить + Изменить категорию + Отслеживание + Нет категорий избранного + Добавить закладку + Удалить закладку + Закладки + Закладка удалена + Закладка добавлена + Отменить + Удалено из истории + DNS поверх HTTPS + Режим по умолчанию + Автоопределение режима чтения + Автоматически определяет, является ли манга веб-комиксом + Отключить оптимизацию батареи + Помогает с фоновой проверкой обновлений + Что-то пошло не так. Пожалуйста, отправьте отчёт разработчикам, чтобы помочь всё исправить. + Отправить + Отключить все + Использовать отпечаток пальца, если доступно + Манга из Вашего избранного + Манга, которую Вы недавно читали + Читаю + Запланировано + Отложено + Заброшено + Завершено + Показать процент прочитанного в истории и избранном + Манга, помеченная как NSFW, никогда не будет добавлена в историю и ваш прогресс чтения не будет сохранен + %1$s%% + Отчёт + Выйти + Перечитываю + Показать индикаторы прогресса чтения + Удаление данных + Может помочь в случае каких-либо проблем. Все авторизации будут аннулированы + Показать все + Неверное доменное имя + Найдите, что почитать во разделе «Обзор» + Назад + Выбрать диапазон + История очищена + Настроить + Закладок пока нет + Закладки удалены + Нет источников манги + Включите источники манги для чтения онлайн + Случайная + Упорядочить + Пусто + Обзор + Нажмите Назад ещё раз, чтобы выйти + Нажмите Назад 2 раза для выхода из приложения + Другой кэш + Опции + Контент не найден или был удален + Гл. %1$d/%2$d Стр. %3$d/%4$d + Показывать информационную панель в режиме чтения + Архив комиксов + Вы можете удалить исходный файл из хранилища, чтобы сэкономить место на нём + Режим инкогнито + Синхронизация + Синхронизируйте ваши данные + Введите электронную почту, чтобы продолжить + Ваша манга будет показана здесь + Аккаунт уже существует + Вы можете создавать закладки во время чтения манги + Подтверждение выхода + Отменено + Очистить всю историю + Последние 2 часа + Вы уверены, что хотите удалить выбранные категории избранного\? \nВся манга в них будет потеряна и это не может быть отменено. - Кэш страниц - %s - %s - Использование хранилища - Доступно - Сохранённая манга - Удалено из избранного - Нет глав - Автоматическое листание - Папка с изображениями - Импорт манги - Импорт завершён - Импорт скоро начнётся - Лента - Сведения об ошибке:<br><tt>%1$s</tt><br><br>1. Попробуйте <a href=%2$s>открыть мангу в веб-браузере</a>, чтобы убедиться, что она доступна в источнике<br>2. Убедитесь, что вы используете <a href=kotatsu://about>последнюю версию Kotatsu</a><br>3. Если возможно, отправьте отчёт об ошибке разработчикам. - Показывать ярлыки последней прочитанной манги - Сделать недавно прочитанную мангу доступной по долгому нажатию на иконку приложения - Нажатие на правый край или нажатие правой клавиши всегда переключает на следующую страницу - Эргономичное управление режимом чтения - Сбросить - Отменить - Сохранить или отменить несохранённые изменения\? - Контрастность - Яркость - Цветокоррекция - Выбранные настройки цвета будут сохранены для этой манги - Не осталось свободного места на накопителе - Масштабирование в режиме манхвы - Показывать слайдер переключения страниц - Включите Wi-Fi или передачу данных, чтобы читать мангу онлайн - Разные языки - Сеть недоступна - Также очистить информацию о новых главах - Внутренняя ошибка сервера (%1$d). Повторите попытку позже - Компактный - Источник отключен - Предварительная загрузка содержимого - Пометить как текущую - Язык - Поделиться логами - Включить логирование - Записывать некоторые действия для отладки - Отображать сомнительный контент - Динамическая - Цветовая схема - Показать в виде сетки - Мику - Аска - Мион - Рикка - Сакура - Службы - Мамими - Канадэ - Чтобы отслеживать прогресс чтения, выберите «Меню» → «Отслеживать» на экране сведений о манге. - Здесь ничего нет - Загрузка началась - Разрешить нестабильные обновления - Предлагать обновления до бета-версий приложения - Пожалуйста, перезапустите приложение, чтобы применить эти изменения - Заголовок UserAgent - Понятно - Нажмите и удерживайте элемент, чтобы изменить их порядок - Вы можете выбрать один или несколько файлов .cbz или .zip, каждый файл будет распознан как отдельная манга. - Вы можете выбрать каталог с архивами или изображениями. Каждый архив (или подкаталог) будет распознан как глава. - Скорость - Импорт ранее созданной резервной копии пользовательских данных - Показать на полке - Найти похожие - Вы можете войти в уже существующий аккаунт или же создать новый - Игнорировать ошибки SSL - Выбрать зеркало автоматически - Автоматически переключать домены для удалённых источников при ошибках, если доступны зеркала - Пауза - Возобновить - Удалить завершённые - Отменить все - Настройки синхронизации - Вы можете использовать собственный сервер синхронизации или сервер по умолчанию. Не изменяйте эту настройку, если не уверены, что делаете. - Адрес сервера - Останавливать загрузку при переключении на мобильную сеть - Приостановлено - Скачивать только через Wi-Fi - Нет, спасибо - Включить - Ещё - Все активные загрузки будут отменены, частично загруженные данные будут утеряны - У Вас нет ни одной загрузки - Загрузки возобновлены - Загрузки приостановлены - Загрузки удалены - Загрузки отменены - Рекомендация: %s - Иногда показывать уведомления с рекомендуемой мангой - Ваша история загрузок будет удалена - Хотите ли Вы получать персонализированные рекомендации манги\? - Переводы - WebView недоступен: проверьте, установлен ли провайдер WebView - Очистить сетевой кеш - Адрес - Тип - Прокси - Порт - %1$s (%2$s) - Неверное значение - \ No newline at end of file + Кэш страниц + %s - %s + Использование хранилища + Доступно + Сохранённая манга + Удалено из избранного + Нет глав + Автоматическое листание + Папка с изображениями + Импорт манги + Импорт завершён + Импорт скоро начнётся + Лента + Сведения об ошибке:<br><tt>%1$s</tt><br><br>1. Попробуйте <a href=%2$s>открыть мангу в веб-браузере</a>, чтобы убедиться, что она доступна в источнике<br>2. Убедитесь, что вы используете <a href=kotatsu://about>последнюю версию Kotatsu</a><br>3. Если возможно, отправьте отчёт об ошибке разработчикам. + Показывать ярлыки последней прочитанной манги + Сделать недавно прочитанную мангу доступной по долгому нажатию на иконку приложения + Нажатие на правый край или нажатие правой клавиши всегда переключает на следующую страницу + Эргономичное управление режимом чтения + Сбросить + Отменить + Сохранить или отменить несохранённые изменения\? + Контрастность + Яркость + Цветокоррекция + Выбранные настройки цвета будут сохранены для этой манги + Не осталось свободного места на накопителе + Масштабирование в режиме манхвы + Показывать слайдер переключения страниц + Включите Wi-Fi или передачу данных, чтобы читать мангу онлайн + Разные языки + Сеть недоступна + Также очистить информацию о новых главах + Внутренняя ошибка сервера (%1$d). Повторите попытку позже + Компактный + Источник отключен + Предварительная загрузка содержимого + Пометить как текущую + Язык + Поделиться логами + Включить логирование + Записывать некоторые действия для отладки + Отображать сомнительный контент + Динамическая + Цветовая схема + Показать в виде сетки + Мику + Аска + Мион + Рикка + Сакура + Службы + Мамими + Канадэ + Чтобы отслеживать прогресс чтения, выберите «Меню» → «Отслеживать» на экране сведений о манге. + Здесь ничего нет + Загрузка началась + Разрешить нестабильные обновления + Предлагать обновления до бета-версий приложения + Пожалуйста, перезапустите приложение, чтобы применить эти изменения + Заголовок UserAgent + Понятно + Нажмите и удерживайте элемент, чтобы изменить их порядок + Вы можете выбрать один или несколько файлов .cbz или .zip, каждый файл будет распознан как отдельная манга. + Вы можете выбрать каталог с архивами или изображениями. Каждый архив (или подкаталог) будет распознан как глава. + Скорость + Импорт ранее созданной резервной копии пользовательских данных + Показать на полке + Найти похожие + Вы можете войти в уже существующий аккаунт или же создать новый + Игнорировать ошибки SSL + Выбрать зеркало автоматически + Автоматически переключать домены для удалённых источников при ошибках, если доступны зеркала + Пауза + Возобновить + Удалить завершённые + Отменить все + Настройки синхронизации + Вы можете использовать собственный сервер синхронизации или сервер по умолчанию. Не изменяйте эту настройку, если не уверены, что делаете. + Адрес сервера + Останавливать загрузку при переключении на мобильную сеть + Приостановлено + Скачивать только через Wi-Fi + Нет, спасибо + Включить + Ещё + Все активные загрузки будут отменены, частично загруженные данные будут утеряны + У Вас нет ни одной загрузки + Загрузки возобновлены + Загрузки приостановлены + Загрузки удалены + Загрузки отменены + Рекомендация: %s + Иногда показывать уведомления с рекомендуемой мангой + Ваша история загрузок будет удалена + Хотите ли Вы получать персонализированные рекомендации манги\? + Переводы + WebView недоступен: проверьте, установлен ли провайдер WebView + Очистить сетевой кеш + Адрес + Тип + Прокси + Порт + %1$s (%2$s) + Неверное значение + diff --git a/app/src/main/res/values-sr/plurals.xml b/app/src/main/res/values-sr/plurals.xml index 815b8609d..43e137252 100644 --- a/app/src/main/res/values-sr/plurals.xml +++ b/app/src/main/res/values-sr/plurals.xml @@ -1,10 +1,5 @@ - - Тотално %1$d странa - Тотално %1$d странице - Тотално %1$d странице - %1$d ставке %1$d ставки diff --git a/app/src/main/res/values-sv/plurals.xml b/app/src/main/res/values-sv/plurals.xml index 6c5a40864..4769abc96 100644 --- a/app/src/main/res/values-sv/plurals.xml +++ b/app/src/main/res/values-sv/plurals.xml @@ -1,9 +1,5 @@ - - Totalt %1$d sida - Totalt %1$d sidor - %1$d artikel %1$d artiklar diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 95ceb535e..7aa01f538 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -54,7 +54,6 @@ Mörkt Denna åtgärden stöds inte Ingen beskrivning - Historik och cache Rensa Rensa all läshistorik permanent\? \"%s\" borttaget från lokal lagring @@ -121,7 +120,6 @@ Vissa enheter har olika systembeteende vilket kan ha sönder bakgrundsjobb. Läs mer Köad - Ladda ned eller läs det saknade kapitlet online. Kapitlet saknas Översätt denna app Översättning @@ -146,7 +144,6 @@ Inaktiverad Kunde inte ladda genrelistan Återställ filter - Hitta genre Välj det språk som du vill läsa manga på. Du kan ändra detta i inställningarna senare. Aldrig Endast på Wi-Fi @@ -158,7 +155,6 @@ Hitta kapitel Inga kapitel i denna manga Utseende - Innehåll Uppdaterar förslag Uteslut genrer Ange genrer som du inte vill få förslag på diff --git a/app/src/main/res/values-tr/plurals.xml b/app/src/main/res/values-tr/plurals.xml index c0c12380a..447fd4fea 100644 --- a/app/src/main/res/values-tr/plurals.xml +++ b/app/src/main/res/values-tr/plurals.xml @@ -1,9 +1,5 @@ - - Toplam %1$d sayfa - Toplam %1$d sayfa - %1$d öge %1$d öge diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index d8eae7df3..bea32c07d 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -1,422 +1,418 @@ - Ağ hatası - Dahili Depolama - Favoriler - Geçmiş - Bölümler - Liste - Detaylı liste - Izgara - Liste modu - Yükleniyor… - Kapat - Tekrar dene - Geçmişi temizle - Hiçbir şey bulunamadı - Geçmiş yok - Oku - Henüz favorileriniz yok - Favoriniz - Yeni kategori - Ekle - Kaydet - Paylaş - %s Paylaş - Ara - Manga ara - İndiriliyor… - İşleniyor… - İndirildi - İndirilenler - Ad - Güncellenme - Yeniler - Puanlama - Litre - Tema - Açık - Koyu - Takip sistemi - Sayfalar - Temizle - Tüm okuma geçmişi kalıcı olarak silinsin mi\? - Kaldır - “%s” yerel depolama alanından sil - Sayfayı kaydet - Resmi paylaş - Popüler - Detaylar - Ayarlar - Kaydet - Bir hata oluştu - Manga kaynakları - Geçmiş ve önbellek - Temizlendi - Devam - Müsait değil - Boş kategori - Kaldır - Sil - Bölüm %1$d / %2$d - Bir ZIP veya CBZ dosyası seçin. - Okuma modu - Izgara boyutu - Webtoon - B|kB|MB|GB|TB - Okuyucu ayarları - Ses butonları - Hata - Küçük resim önbelleğini temizle - Yalnızca hareketler - Alan adi - Web tarayıcısında aç - Yeni bölümler - Bildirim ayarları - Bildirim sesi - LED göstergesi - Titreşim - Diğer depolama - Güncellemeler - Kısayol oluştur… - İçe aktar - Mangayı sil - Bilgi işleniyor… - Sıralama düzeni - Açıklama yok - Bu işlem desteklenmiyor - Standart - Sayfa önbelleğini temizle - %s üzerinde ara - Dahili depolama - Bildirimler - Sayfaları değiştir - Kaydet - İndir - İndirilenler klasörü - Harici depolama - Uygulamanın yeni bir sürümü mevcut - Favori kategoriler - Bitti - Sonra oku - Sayfa animasyonu - Kullanılabilir depolama alanı yok - “%s” cihazdan kalıcı olarak silinsin mi\? - Arama geçmişini temizle - Burası biraz boş… - Ekranı döndür - Ölçek modu - Yüksekliğe sığdır - Siyah - Başlangıçta tut - Akışı temizle - Bu eksik bölümü çevrim içi olarak indirin veya okuyun. - Yedekten geri yükle - Güncelle - Oturum aç - Bitti - Hakkında - Bu içeriği görüntülemek için oturum açın - Onayla - Yetkilendirildi - Az önce - Kenar dokunuşları - Bu mangada %s var. Hepsi kaydedilsin mi\? - %1$d / %2$d açık - Sorguyu yeniden biçimlendirmeyi deneyin. - Okuduklarınız burada görüntülenecek - Yan menüde ne okuyacağınızı bulun. - Önce bir şey kaydedin - Çevrim içi kaynaklardan kaydedin veya dosyaları içe aktarın. - Raf - Son - Boyut: %s - Temizlendi - Parola gir - Kotatsu başlatılırken parola sor - Güncellemeleri ara - Güncelleme akışını temizle - Akış güncellemesi yakında başlayacak - Sürüm %s - Güncellemeleri denetle - Merkeze sığdır - Genişliğe sığdır - AMOLED ekranlarda daha az güç kullanır - Yedekle ve geri yükle - Veri yedeği oluştur - Geri yüklendi - Hazırlanıyor… - Dün - Grup - Sessiz - Çöz - Çerezleri temizle - Öntanımlı: %s - Ters - Parola 4 veya daha fazla karakterden oluşmalıdır - Hoş geldiniz - Sıraya alındı - Bölüm eksik - Bu uygulamayı çevirin - Çeviri - Devam ediyor - Tüm kaynaklardaki oturumunuz kapatılacak - Kullanılan kaynaklar - Kullanılabilir kaynaklar - Uygunsuz mangayı geçmişten hariç tut - Numaralı sayfalar - Arama sonuçları - Parolayı tekrarla - Denetleme - Yanlış parola - Geçmişinizin ve favorilerinizin yedeğini oluşturabilir ve bunları geri yükleyebilirsiniz - Uzun zaman önce - Bugün - Güncelleme yok - Tüm favoriler - Okuduklarınızın yeni bölümleri burada gösterilir - Yeni sürüm: %s - Uygulamayı koru - Parolalar eşleşmiyor - Sağdan-sola - Yeni kategori - Dosya bulunamadı - Tüm veriler geri yüklendi - Veriler geri yüklendi, ancak hatalar var - Tekrar denemek için dokunun - İleri - CAPTCHA gerekli - Tüm çerezler kaldırıldı - Seçilen yapılandırma bu manga için hatırlanacak - Tüm güncelleme geçmişi kalıcı olarak silinsin mi\? - Uygulamayı başlatmak için bir parola girin - Tüm son arama sorguları kalıcı olarak kaldırılsın mı\? - Yedek kaydedildi - Türler - Öntanımlı - %s üzerinde oturum açma desteklenmiyor - Daha fazla oku - Bazı aygıtların arka plan görevlerini bozabilecek farklı sistem davranışları vardır. - Ekran görüntüsü politikası - Uygunsuzlarda engelle - Her zaman engelle - İzin ver - Yeni bölümleri denetle - Öneriler - Önerileri etkinleştir - Tercihlerinize göre manga önerileri alın - Tüm veriler sadece bu cihaz üzerinde yerel olarak işlenir ve asla herhangi bir yere satılmaz. - Manga okumaya başladıktan sonra kişiselleştirilmiş öneriler alacaksınız - Uygunsuz manga önerme - Etkin - Devre dışı - Türler listesi yüklenemiyor - Filtreyi sıfırla - Tür bul - Manga okumak istediğiniz dilleri seçin. Daha sonra ayarlardan değiştirebilirsiniz. - Her zaman - Hiçbir zaman - Yalnızca Wi-Fi\'de - Sayfaları önceden yükle - %s olarak oturum açıldı - 18+ - Çeşitli diller - Bölüm bul - Bu mangada bölüm yok - %%%1$s - İçerik - Öneriler güncelleniyor - Görünüm - Türleri hariç tut - Önerilerde görmek istemediğiniz türleri belirtin - Seçilen ögeler aygıttan kalıcı olarak silinsin mi\? - Kaldırma tamamlandı - Bölümler arka planda kaldırılacak. - İndirmeyi yavaşlat - IP adresinizin engellenmesinden kaçınmanıza yardımcı olur - Kaydedilen manga işleme - Gizle - Yeni manga kaynakları var - Bildirim almayacaksınız ancak yeni bölümler listelerde vurgulanacak - Bildirimleri etkinleştir - Yeni bölümleri denetle ve bildirim gönder - Okuduğunuz manga güncellemeleri hakkında bildirim alacaksınız - Favori kategori yok - Ad - Düzenle - Kategoriyi düzenle - Yer imi ekle - Yer imini kaldır - Yer imleri - Yer imi kaldırıldı - Yer imi eklendi - Geri al - Geçmişten kaldırıldı - HTTPS üzerinden DNS - Okuyucu modunu otomatik algıla - Manganın webtoon olup olmadığını otomatik olarak algıla - Öntanımlı mod - Pil iyileştirmesini devre dışı bırak - Arka planda güncelleme denetimlerine yardımcı olur - Bir şeyler yanlış gitti. Düzeltmemize yardımcı olması için lütfen geliştiricilere bir hata bildirimi gönderin. - Gönder - Tümünü devre dışı bırak - Varsa parmak izi kullan - Favorilerinizden mangalar - Son okuduğunuz mangalar - Bildir - İzleme - Oturumu kapat - Okunuyor - Tamamlandı - Okuma ilerleme göstergelerini göster - Verileri sil - Geçmişte ve favorilerde okunma yüzdesini göster - Uygunsuz olarak işaretlenen mangalar asla geçmişe eklenmeyecek ve ilerlemeniz kaydedilmeyecektir - Bazı sorunlarda yardımcı olabilir. Tüm yetkilendirmeler geçersiz kılınacaktır - Beklemede - Bırakıldı - Planlandı - Yeniden okunuyor - Tümünü göster - Geçersiz etki alanı - Aralık seç - İçerik bulunamadı veya kaldırıldı - Manganız burada görüntülenecek - İptal edilmiş - Hesap zaten var - Geri - Senkronizasyon - Verini yedekle - Devam etmek için E-Postanızı girin - Tüm gecmişi temizle - Son 2 saat - Geçmiş temizlendi - Yönet - Yer işareti yok - Manga okurken yer işareti oluşturabilirsiniz - Yer işaretleri kaldırıldı - Manga kaynağı yok - Çevrimiçi manga okumak için manga kaynaklarını aktif edin - Rastgele - Boş - Keşfet - Çıkmak için tekrar Geri tıkla - Çıkmak için iki defa Geri tıkla - Favorilerden kaldırıldı - Çıkış doğrulaması - Çizgi roman arşivi - Hata ayrıntıları:<br><tt>%1$s</tt><br><br>1.Mangayı <a href=%2$s>kaynağında mevcut olduğuna emin olmak için</a> bir web tarayıcısında açın<br>2. <a href=kotatsu://about> Kotatsunun son sürümünü kullandığnızdan emin olun.</a>/br> 3. Mevcutsa, geliştiricilere bir hata reporu gönderin. - «Keşfet» kısmında neler okuyacağınızı bulun - Seçilen favori kategorileri silmek istediğinizden emin misiniz\? + Ağ hatası + Dahili Depolama + Favoriler + Geçmiş + Bölümler + Liste + Detaylı liste + Izgara + Liste modu + Yükleniyor… + Kapat + Tekrar dene + Geçmişi temizle + Hiçbir şey bulunamadı + Geçmiş yok + Oku + Henüz favorileriniz yok + Favoriniz + Yeni kategori + Ekle + Kaydet + Paylaş + %s Paylaş + Ara + Manga ara + İndiriliyor… + İşleniyor… + İndirildi + İndirilenler + Ad + Güncellenme + Yeniler + Puanlama + Litre + Tema + Açık + Koyu + Takip sistemi + Sayfalar + Temizle + Tüm okuma geçmişi kalıcı olarak silinsin mi\? + Kaldır + “%s” yerel depolama alanından sil + Sayfayı kaydet + Resmi paylaş + Popüler + Detaylar + Ayarlar + Kaydet + Bir hata oluştu + Manga kaynakları + Temizlendi + Devam + Müsait değil + Boş kategori + Kaldır + Sil + Bölüm %1$d / %2$d + Bir ZIP veya CBZ dosyası seçin. + Okuma modu + Izgara boyutu + Webtoon + B|kB|MB|GB|TB + Okuyucu ayarları + Ses butonları + Hata + Küçük resim önbelleğini temizle + Yalnızca hareketler + Alan adi + Web tarayıcısında aç + Yeni bölümler + Bildirim ayarları + Bildirim sesi + LED göstergesi + Titreşim + Diğer depolama + Güncellemeler + Kısayol oluştur… + İçe aktar + Mangayı sil + Bilgi işleniyor… + Sıralama düzeni + Açıklama yok + Bu işlem desteklenmiyor + Standart + Sayfa önbelleğini temizle + %s üzerinde ara + Dahili depolama + Bildirimler + Sayfaları değiştir + Kaydet + İndir + İndirilenler klasörü + Harici depolama + Uygulamanın yeni bir sürümü mevcut + Favori kategoriler + Bitti + Sonra oku + Sayfa animasyonu + Kullanılabilir depolama alanı yok + “%s” cihazdan kalıcı olarak silinsin mi\? + Arama geçmişini temizle + Burası biraz boş… + Ekranı döndür + Ölçek modu + Yüksekliğe sığdır + Siyah + Başlangıçta tut + Akışı temizle + Yedekten geri yükle + Güncelle + Oturum aç + Bitti + Hakkında + Bu içeriği görüntülemek için oturum açın + Onayla + Yetkilendirildi + Az önce + Kenar dokunuşları + Bu mangada %s var. Hepsi kaydedilsin mi\? + %1$d / %2$d açık + Sorguyu yeniden biçimlendirmeyi deneyin. + Okuduklarınız burada görüntülenecek + Yan menüde ne okuyacağınızı bulun. + Önce bir şey kaydedin + Çevrim içi kaynaklardan kaydedin veya dosyaları içe aktarın. + Raf + Son + Boyut: %s + Temizlendi + Parola gir + Kotatsu başlatılırken parola sor + Güncellemeleri ara + Güncelleme akışını temizle + Akış güncellemesi yakında başlayacak + Sürüm %s + Güncellemeleri denetle + Merkeze sığdır + Genişliğe sığdır + AMOLED ekranlarda daha az güç kullanır + Yedekle ve geri yükle + Veri yedeği oluştur + Geri yüklendi + Hazırlanıyor… + Dün + Grup + Sessiz + Çöz + Çerezleri temizle + Öntanımlı: %s + Ters + Parola 4 veya daha fazla karakterden oluşmalıdır + Hoş geldiniz + Sıraya alındı + Bölüm eksik + Bu uygulamayı çevirin + Çeviri + Devam ediyor + Tüm kaynaklardaki oturumunuz kapatılacak + Kullanılan kaynaklar + Kullanılabilir kaynaklar + Uygunsuz mangayı geçmişten hariç tut + Numaralı sayfalar + Arama sonuçları + Parolayı tekrarla + Denetleme + Yanlış parola + Geçmişinizin ve favorilerinizin yedeğini oluşturabilir ve bunları geri yükleyebilirsiniz + Uzun zaman önce + Bugün + Güncelleme yok + Tüm favoriler + Okuduklarınızın yeni bölümleri burada gösterilir + Yeni sürüm: %s + Uygulamayı koru + Parolalar eşleşmiyor + Sağdan-sola + Yeni kategori + Dosya bulunamadı + Tüm veriler geri yüklendi + Veriler geri yüklendi, ancak hatalar var + Tekrar denemek için dokunun + İleri + CAPTCHA gerekli + Tüm çerezler kaldırıldı + Seçilen yapılandırma bu manga için hatırlanacak + Tüm güncelleme geçmişi kalıcı olarak silinsin mi\? + Uygulamayı başlatmak için bir parola girin + Tüm son arama sorguları kalıcı olarak kaldırılsın mı\? + Yedek kaydedildi + Türler + Öntanımlı + %s üzerinde oturum açma desteklenmiyor + Daha fazla oku + Bazı aygıtların arka plan görevlerini bozabilecek farklı sistem davranışları vardır. + Ekran görüntüsü politikası + Uygunsuzlarda engelle + Her zaman engelle + İzin ver + Yeni bölümleri denetle + Öneriler + Önerileri etkinleştir + Tercihlerinize göre manga önerileri alın + Tüm veriler sadece bu cihaz üzerinde yerel olarak işlenir ve asla herhangi bir yere satılmaz. + Manga okumaya başladıktan sonra kişiselleştirilmiş öneriler alacaksınız + Uygunsuz manga önerme + Etkin + Devre dışı + Türler listesi yüklenemiyor + Filtreyi sıfırla + Manga okumak istediğiniz dilleri seçin. Daha sonra ayarlardan değiştirebilirsiniz. + Her zaman + Hiçbir zaman + Yalnızca Wi-Fi\'de + Sayfaları önceden yükle + %s olarak oturum açıldı + 18+ + Çeşitli diller + Bölüm bul + Bu mangada bölüm yok + %%%1$s + Öneriler güncelleniyor + Görünüm + Türleri hariç tut + Önerilerde görmek istemediğiniz türleri belirtin + Seçilen ögeler aygıttan kalıcı olarak silinsin mi\? + Kaldırma tamamlandı + Bölümler arka planda kaldırılacak. + İndirmeyi yavaşlat + IP adresinizin engellenmesinden kaçınmanıza yardımcı olur + Kaydedilen manga işleme + Gizle + Yeni manga kaynakları var + Bildirim almayacaksınız ancak yeni bölümler listelerde vurgulanacak + Bildirimleri etkinleştir + Yeni bölümleri denetle ve bildirim gönder + Okuduğunuz manga güncellemeleri hakkında bildirim alacaksınız + Favori kategori yok + Ad + Düzenle + Kategoriyi düzenle + Yer imi ekle + Yer imini kaldır + Yer imleri + Yer imi kaldırıldı + Yer imi eklendi + Geri al + Geçmişten kaldırıldı + HTTPS üzerinden DNS + Okuyucu modunu otomatik algıla + Manganın webtoon olup olmadığını otomatik olarak algıla + Öntanımlı mod + Pil iyileştirmesini devre dışı bırak + Arka planda güncelleme denetimlerine yardımcı olur + Bir şeyler yanlış gitti. Düzeltmemize yardımcı olması için lütfen geliştiricilere bir hata bildirimi gönderin. + Gönder + Tümünü devre dışı bırak + Varsa parmak izi kullan + Favorilerinizden mangalar + Son okuduğunuz mangalar + Bildir + İzleme + Oturumu kapat + Okunuyor + Tamamlandı + Okuma ilerleme göstergelerini göster + Verileri sil + Geçmişte ve favorilerde okunma yüzdesini göster + Uygunsuz olarak işaretlenen mangalar asla geçmişe eklenmeyecek ve ilerlemeniz kaydedilmeyecektir + Bazı sorunlarda yardımcı olabilir. Tüm yetkilendirmeler geçersiz kılınacaktır + Beklemede + Bırakıldı + Planlandı + Yeniden okunuyor + Tümünü göster + Geçersiz etki alanı + Aralık seç + İçerik bulunamadı veya kaldırıldı + Manganız burada görüntülenecek + İptal edilmiş + Hesap zaten var + Geri + Senkronizasyon + Verini yedekle + Devam etmek için E-Postanızı girin + Tüm gecmişi temizle + Son 2 saat + Geçmiş temizlendi + Yönet + Yer işareti yok + Manga okurken yer işareti oluşturabilirsiniz + Yer işaretleri kaldırıldı + Manga kaynağı yok + Çevrimiçi manga okumak için manga kaynaklarını aktif edin + Rastgele + Boş + Keşfet + Çıkmak için tekrar Geri tıkla + Çıkmak için iki defa Geri tıkla + Favorilerden kaldırıldı + Çıkış doğrulaması + Çizgi roman arşivi + Hata ayrıntıları:<br><tt>%1$s</tt><br><br>1.Mangayı <a href=%2$s>kaynağında mevcut olduğuna emin olmak için</a> bir web tarayıcısında açın<br>2. <a href=kotatsu://about> Kotatsunun son sürümünü kullandığnızdan emin olun.</a>/br> 3. Mevcutsa, geliştiricilere bir hata reporu gönderin. + «Keşfet» kısmında neler okuyacağınızı bulun + Seçilen favori kategorileri silmek istediğinizden emin misiniz\? \nİçindeki tüm mangalar kaybolur ve bu işlem geri alınamaz. - Yeniden sırala - Sayfa önbelleği - Diğer önbellekler - Depolama kullanımı - Mevcut - %s - %s - Seçenekler - Gizli mod - Bölüm yok - Otomatik kaydır - Böl. %1$d/%2$d Sayf. %3$d/%4$d - Okuyucuda bilgi çubuğu göster - Resimlerle klasör - Manga içe aktarılıyor - İçe aktarım tamamlandı - Yer açmak için orijinal dosyayı depolamadan silebilirsiniz - İçe aktarım birazdan başlayacak - Akış - En son manga kısayollarını göster - Ergonomik okuyucu kontrol - Renk düzeltme - Parlaklık - Kontrast - Sıfırla - Seçilen renk ayarları bu manga için hatırlanacaktır - Kaydedilmeyen değişiklikler kaydedilsin mi yoksa atılsın mı\? - Yoksay - Cihazda yer yok - Webtoon yakınlaştırma - Sayfa değiştirme kaydırıcısını göster - Ayrıca yeni bölümler hakkındaki bilgileri temizle - Sıkı - Farklı diller - Ağ kullanılamıyor - Çevrim içi manga okumak için Wi-Fi veya mobil ağı açın - Sunucu tarafı hatası (%1$d). Lütfen daha sonra tekrar deneyin - Kaydedilen mangalar - Uygulama simgesine uzun basarak son mangaları kullanılabilir hale getirin - Sağ kenara dokunulduğunda veya sağ tuşa basıldığında her zaman bir sonraki sayfaya geçilir - Kaynak devre dışı - İçerik ön yüklemesi - Geçerli olarak işaretle - Dil - Günlükleri paylaş - Günlük kaydını etkinleştir - Hata ayıklama amacıyla bazı eylemleri kaydedin - Şüpheli içeriği göster - Hizmetler - Okuma ilerlemesini izlemek için manga ayrıntıları ekranında Menü → İzle\'yi seçin. - burada hiçbir şey yok - Dinamik - renk vurgusu - Izgara görünümünde göster - Mamimi - Kanade - UserAgent başlığı - Uygulamanın beta sürümleri için güncellemeler öner - Kararsız güncellemelere izin ver - İndirme başladı - Miku - Asuka - Mion - Rikka - Sakura - Bu değişiklikleri uygulamak için lütfen uygulamayı yeniden başlatın - Benzerini bul - Çeviriler - WebView kullanılamıyor: WebView sağlayıcısının kurulu olup olmadığını kontrol edin - Etkinleştir - Hayır teşekkürler - İnternet geçmişini temizle - Eşitleme seçenekleri - Sunucu adresi - "Şirket içinde barındırılan bir eşitleme sunucusu veya varsayılan bir sunucu kullanabilirsiniz. Ne yaptığınızdan emin değilseniz bunu değiştirmeyin." - Yansıtmalar varsa, hatalarda uzak kaynaklar için etki alanlarını otomatik olarak değiştir - Mobil ağa geçerken indirmeyi durdur - Bitirilenleri kaldır - Hepsini iptal et - Sadece Wi-Fi ile indir - Anladım - Yeniden sıralamak için bir öğeye dokunun ve basılı tutun - Bir veya daha fazla .cbz veya .zip dosyası seçebilirsiniz, her dosya ayrı bir manga olarak tanınacaktır. - Arşivler veya resimler içeren bir dizin seçebilirsiniz. Her arşiv (veya alt dizin) bir bölüm olarak tanınacaktır. - Hız - Kullanıcı verilerinin önceden oluşturulmuş bir yedeğini içe aktarın - Rafta Göster - Mevcut bir hesapta oturum açabilir veya yeni bir hesap oluşturabilirsiniz. - SSL hatalarını görmezden gel - Durdur - Devam et - Durduruldu - Öneri:%s - Bazen manga öneri bildirimlerilerini göster - Daha fazla - Tüm aktif indirmeler iptal edilecek, kısmen indirilen veriler kaybolacak - İndirme geçmişin tamamen silinecek - Hiçbir indirmeniz yok - İndirmeler devam ettirildi - İndirmeler durduruldu - İndirmeler silindi - Aynayı otomatik olarak seç - İndirmeler iptal edildi - Kişiselleştirilmiş manga önerileri almak istiyor musunuz\? - Adres - Tür - %1$s (%2$s) - Menü - Proxy - Geçersiz değer - \ No newline at end of file + Yeniden sırala + Sayfa önbelleği + Diğer önbellekler + Depolama kullanımı + Mevcut + %s - %s + Seçenekler + Gizli mod + Bölüm yok + Otomatik kaydır + Böl. %1$d/%2$d Sayf. %3$d/%4$d + Okuyucuda bilgi çubuğu göster + Resimlerle klasör + Manga içe aktarılıyor + İçe aktarım tamamlandı + Yer açmak için orijinal dosyayı depolamadan silebilirsiniz + İçe aktarım birazdan başlayacak + Akış + En son manga kısayollarını göster + Ergonomik okuyucu kontrol + Renk düzeltme + Parlaklık + Kontrast + Sıfırla + Seçilen renk ayarları bu manga için hatırlanacaktır + Kaydedilmeyen değişiklikler kaydedilsin mi yoksa atılsın mı\? + Yoksay + Cihazda yer yok + Webtoon yakınlaştırma + Sayfa değiştirme kaydırıcısını göster + Ayrıca yeni bölümler hakkındaki bilgileri temizle + Sıkı + Farklı diller + Ağ kullanılamıyor + Çevrim içi manga okumak için Wi-Fi veya mobil ağı açın + Sunucu tarafı hatası (%1$d). Lütfen daha sonra tekrar deneyin + Kaydedilen mangalar + Uygulama simgesine uzun basarak son mangaları kullanılabilir hale getirin + Sağ kenara dokunulduğunda veya sağ tuşa basıldığında her zaman bir sonraki sayfaya geçilir + Kaynak devre dışı + İçerik ön yüklemesi + Geçerli olarak işaretle + Dil + Günlükleri paylaş + Günlük kaydını etkinleştir + Hata ayıklama amacıyla bazı eylemleri kaydedin + Şüpheli içeriği göster + Hizmetler + Okuma ilerlemesini izlemek için manga ayrıntıları ekranında Menü → İzle\'yi seçin. + burada hiçbir şey yok + Dinamik + renk vurgusu + Izgara görünümünde göster + Mamimi + Kanade + UserAgent başlığı + Uygulamanın beta sürümleri için güncellemeler öner + Kararsız güncellemelere izin ver + İndirme başladı + Miku + Asuka + Mion + Rikka + Sakura + Bu değişiklikleri uygulamak için lütfen uygulamayı yeniden başlatın + Benzerini bul + Çeviriler + WebView kullanılamıyor: WebView sağlayıcısının kurulu olup olmadığını kontrol edin + Etkinleştir + Hayır teşekkürler + İnternet geçmişini temizle + Eşitleme seçenekleri + Sunucu adresi + "Şirket içinde barındırılan bir eşitleme sunucusu veya varsayılan bir sunucu kullanabilirsiniz. Ne yaptığınızdan emin değilseniz bunu değiştirmeyin." + Yansıtmalar varsa, hatalarda uzak kaynaklar için etki alanlarını otomatik olarak değiştir + Mobil ağa geçerken indirmeyi durdur + Bitirilenleri kaldır + Hepsini iptal et + Sadece Wi-Fi ile indir + Anladım + Yeniden sıralamak için bir öğeye dokunun ve basılı tutun + Bir veya daha fazla .cbz veya .zip dosyası seçebilirsiniz, her dosya ayrı bir manga olarak tanınacaktır. + Arşivler veya resimler içeren bir dizin seçebilirsiniz. Her arşiv (veya alt dizin) bir bölüm olarak tanınacaktır. + Hız + Kullanıcı verilerinin önceden oluşturulmuş bir yedeğini içe aktarın + Rafta Göster + Mevcut bir hesapta oturum açabilir veya yeni bir hesap oluşturabilirsiniz. + SSL hatalarını görmezden gel + Durdur + Devam et + Durduruldu + Öneri:%s + Bazen manga öneri bildirimlerilerini göster + Daha fazla + Tüm aktif indirmeler iptal edilecek, kısmen indirilen veriler kaybolacak + İndirme geçmişin tamamen silinecek + Hiçbir indirmeniz yok + İndirmeler devam ettirildi + İndirmeler durduruldu + İndirmeler silindi + Aynayı otomatik olarak seç + İndirmeler iptal edildi + Kişiselleştirilmiş manga önerileri almak istiyor musunuz\? + Adres + Tür + %1$s (%2$s) + Menü + Proxy + Geçersiz değer + diff --git a/app/src/main/res/values-uk/plurals.xml b/app/src/main/res/values-uk/plurals.xml index 1db12997c..2219d916a 100644 --- a/app/src/main/res/values-uk/plurals.xml +++ b/app/src/main/res/values-uk/plurals.xml @@ -12,12 +12,6 @@ %1$d хвилин тому %1$d хвилин тому - - Всього %1$d сторінка - Всього %1$d сторінки - Всього %1$d сторінок - Всього %1$d сторінок - %1$d годину тому %1$d години тому diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index c9ab878da..e7c74087b 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -1,422 +1,418 @@ - Видалити - Нічого не знайдено - Додати до улюблених - Очистити історію - Історії ще немає - Додати - Зберегти - Локальне сховище - Помилка мережі - Деталі - Спробуйте ще раз - Улюблених ще немає - Нова категорія - Завантажено - Уподобання - Історія - Сталася помилка - Розділи - Список - Детальний список - Режим списку - Налаштування - Джерела манги - Завантаження… - Обчислення… - Розділ %1$d із %2$d - Закрити - Читати - Таблиця - Поділитися - Створити ярлик… - Поділитися %s - Пошук - Пошук манґи - Обробка… - Ім\'я - Популярна - Оновлена - Нова - Рейтинг - Порядок сортування - Фільтр - Тема - Світла - Темна - Сторінки - Очистити всю історію читання перманентно\? - Видалити - \"%s\" видалено з локального сховища - Зберегти сторінку - Збережено - Поділитись зображенням - Ця операція не підтримується - Виберіть файл ZIP або CBZ. - Немає опису - Історія та кеш - Очистити кеш сторінок - Б|кБ|МБ|ГБ|ТБ - Стандартний - Манхва - Режим читання - Розмір сітки - Пошук по %s - Видалити манґу - Видалити \"%s\" з пристрою перманентно\? - Налаштування читача - Перегортання сторінок - Кнопки гучності - Помилка - Очистити кеш мініатюр - Очистити історію пошуку - Очищено - Тільки жести - Внутрішнє сховище - Зовнішнє сховище - Домен - Доступна нова версія застосунку - Ця манґа має %s. Зберегти все це\? - Зберегти - Сповіщення - Увімкнено %1$d з %2$d - Нові розділи - Завантажити - Вібрація - Улюблені категорії - Видалити - Тут якось пусто… - Спробуйте переформулювати запит. - Те, що ви читаєте, буде показано тут - Знайдіть, що читати, у бічному меню. - Спочатку збережіть щось - Збережіть його з онлайн-джерела або імпортуйте файли. - Полиця - Недавні - Анімація перегортання - Тека для завантажень - Інше сховище - Готово - Усі улюблені - Порожня категорія - Прочитати пізніше - Оновлення - Нова версія: %s - Розмір: %s - Очистити стрічку оновлень - Очищено - Повернути екран - Оновити - Оновлення скоро почнеться - Стежити за оновленнями - Не перевіряти - Неправильний пароль - Захистити застосунок - Запитувати пароль під час запуску Kotatsu - Повторіть пароль - Паролі не співпадають - Про застосунок - Версія %s - Перевірити наявність оновлень - Немає доступних оновлень - Нова категорія - Режим масштабування - Вмістити в екран - Підігнати по висоті - Підігнати по ширині - Вихідний розмір - Чорна - Споживає менше енергії на екранах AMOLED - Резервне копіювання та відновлення - Відновлено - Підготовка… - Файл не знайдено - Дані відновлено, але є деякі помилки - Ви можете створити резервну копію своєї історії та уподобань і відновити їх - Тільки що - Торкніться, щоб спробувати ще раз - Обраний режим буде запам\'ятован для цієї манги - Потрібна CAPTCHA - Пройти - Очистити кукі - Всі кукі були видалені - Очистити стрічку - Перевірити нові розділи - В зворотньому порядку - Увійти - Увійдіть, щоб переглянути цей вміст - За замовчуванням: %s - Далі - Введіть пароль для запуску застосунку - Підтвердити - Пароль має містити 4 символи або більше - Ласкаво просимо - Резервна копія збережена - Докладніше - У черзі - Допомогти з перекладом застосунку - Переклад - Авторизація виконана - Вхід на %s не підтримується - Ви вийдете з усіх джерел - Завершена - Триває - Виключити NSFW манґу з історії - Показувати номери сторінок - Включені джерела - Політика щодо знімків екрана - Дозволити - Пропонувати манґу на основі ваших уподобань - Усі дані аналізуються лише локально на цьому пристрої й ніколи нікуди не надсилаються. - Почніть читати манґу, і ви отримаєте персоналізовані пропозиції - Увімкнено - Вимкнено - Скинути фільтр - Знайти жанр - Виберіть мови, якими ви хочете читати манґу. Це можливо змінити пізніше в налаштуваннях. - Тільки по Wi-Fi - Попереднє завантаження сторінок - Ви увійшли як %s - 18+ - Різні мови - Знайти розділ - Немає розділів у цій манзі - %1$s%% - Зміст - Оновлення пропозицій - Видалити вибрані елементи з пристрою назавжди\? - Видалення завершено - Сповільнення завантаження - Обробка збереженої манґи - Приховати - Доступні нові джерела манґи - Завантаження… - Очистити - Завантаження - Як в системі - Завантажте або прочитайте цей відсутній розділ онлайн. - Розділ відсутній - Жанри - За замовчуванням - Завжди - Продовжити - Імпорт - Натискання по краях - Налаштування сповіщень - Відкрити у веб-браузері - Недоступно - Немає доступного сховища - Нові розділи того, що ви читаєте, показано тут - Результати пошуку - Введіть пароль - Звук сповіщень - Світлодіодний індикатор - Учора - Справа наліво (←) - Створити резервну копію - Відновити з резервної копії - Всі дані були відновлені - Групувати - Сьогодні - Без звуку - Давно - Очистити всю історію оновлень назавжди\? - Деякі пристрої мають різну поведінку системи, що може порушити фонові завдання. - Видалити всі останні пошукові запити назавжди\? - Доступні джерела - Блок на NSFW - Завжди блокувати - Пропозиції - Увімкнути пропозиції - Не пропонувати NSFW манґу - Не вдалося завантажити список жанрів - Ніколи - Зовнішній вигляд - Виключити жанри - Укажіть жанри, які ви не хочете бачити в пропозиціях - Допомагає уникнути блокування вашої IP-адреси - Розділи буде видалено у фоновому режимі - Перевіряти наявність нових розділів і повідомляти про них - Ви будете отримувати повідомлення про оновлення манґи, яку ви читаєте - Увімкнути сповіщення - Ви не будете отримувати повідомлення, але нові розділи будуть відображатися у списку - Немає улюблених категорій - Назва - Змінити - Змінити категорію - Додати закладку - Видалити закладку - Закладки - Закладка видалена - Додано закладку - Відмінити - Видалено з історії - DNS через HTTPS - Режим за замовчуванням - Автоматично визначати, чи є манґа вебтуном - Автовизначення режиму читання - Вимкнути оптимізацію акумулятора - Допомагає з перевірками фонових оновлень - Щось пішло не так. Будь ласка, надішліть звіт про помилку розробникам, щоб допомогти нам її виправити. - Надіслати - Вимкнути все - Використовувати відбиток пальця, якщо доступно - Манга з Вашого улюбленого - Манга, яку Ви нещодавно читали - Недійсний домен - Звіт - Відстеження - Вийти - Заплановано - Читаю - Перечитую - Завершено - Відкладено - Занедбано - Показувати індикатори прогресу читання - Видалення даних - Показати відсоток прочитаного в історії та обраному - Манґа, позначена як NSFW, ніколи не буде додана до історії і ваш прогрес не буде збережений - Може допомогти в разі виникнення проблем. Усі авторизації будуть анульовані - Показати всі - Виберіть діапазон - Вміст не знайдено або видалено - Ваша манга буде відображатися тут - Знайдіть, що почитати у розділі «Огляд» - Назад - Введіть свою електронну пошту, щоб продовжити - Історія очищена - Керувати - Закладок ще немає - Ви можете створювати закладки під час читання манґи - Закладки видалено - Немає джерел манґи - Увімкніть джерела манґи, щоб читати онлайн - Випадкова - Ви впевнені, що бажаєте видалити вибрані улюблені категорії\? + Видалити + Нічого не знайдено + Додати до улюблених + Очистити історію + Історії ще немає + Додати + Зберегти + Локальне сховище + Помилка мережі + Деталі + Спробуйте ще раз + Улюблених ще немає + Нова категорія + Завантажено + Уподобання + Історія + Сталася помилка + Розділи + Список + Детальний список + Режим списку + Налаштування + Джерела манги + Завантаження… + Обчислення… + Розділ %1$d із %2$d + Закрити + Читати + Таблиця + Поділитися + Створити ярлик… + Поділитися %s + Пошук + Пошук манґи + Обробка… + Ім\'я + Популярна + Оновлена + Нова + Рейтинг + Порядок сортування + Фільтр + Тема + Світла + Темна + Сторінки + Очистити всю історію читання перманентно\? + Видалити + \"%s\" видалено з локального сховища + Зберегти сторінку + Збережено + Поділитись зображенням + Ця операція не підтримується + Виберіть файл ZIP або CBZ. + Немає опису + Очистити кеш сторінок + Б|кБ|МБ|ГБ|ТБ + Стандартний + Манхва + Режим читання + Розмір сітки + Пошук по %s + Видалити манґу + Видалити \"%s\" з пристрою перманентно\? + Налаштування читача + Перегортання сторінок + Кнопки гучності + Помилка + Очистити кеш мініатюр + Очистити історію пошуку + Очищено + Тільки жести + Внутрішнє сховище + Зовнішнє сховище + Домен + Доступна нова версія застосунку + Ця манґа має %s. Зберегти все це\? + Зберегти + Сповіщення + Увімкнено %1$d з %2$d + Нові розділи + Завантажити + Вібрація + Улюблені категорії + Видалити + Тут якось пусто… + Спробуйте переформулювати запит. + Те, що ви читаєте, буде показано тут + Знайдіть, що читати, у бічному меню. + Спочатку збережіть щось + Збережіть його з онлайн-джерела або імпортуйте файли. + Полиця + Недавні + Анімація перегортання + Тека для завантажень + Інше сховище + Готово + Усі улюблені + Порожня категорія + Прочитати пізніше + Оновлення + Нова версія: %s + Розмір: %s + Очистити стрічку оновлень + Очищено + Повернути екран + Оновити + Оновлення скоро почнеться + Стежити за оновленнями + Не перевіряти + Неправильний пароль + Захистити застосунок + Запитувати пароль під час запуску Kotatsu + Повторіть пароль + Паролі не співпадають + Про застосунок + Версія %s + Перевірити наявність оновлень + Немає доступних оновлень + Нова категорія + Режим масштабування + Вмістити в екран + Підігнати по висоті + Підігнати по ширині + Вихідний розмір + Чорна + Споживає менше енергії на екранах AMOLED + Резервне копіювання та відновлення + Відновлено + Підготовка… + Файл не знайдено + Дані відновлено, але є деякі помилки + Ви можете створити резервну копію своєї історії та уподобань і відновити їх + Тільки що + Торкніться, щоб спробувати ще раз + Обраний режим буде запам\'ятован для цієї манги + Потрібна CAPTCHA + Пройти + Очистити кукі + Всі кукі були видалені + Очистити стрічку + Перевірити нові розділи + В зворотньому порядку + Увійти + Увійдіть, щоб переглянути цей вміст + За замовчуванням: %s + Далі + Введіть пароль для запуску застосунку + Підтвердити + Пароль має містити 4 символи або більше + Ласкаво просимо + Резервна копія збережена + Докладніше + У черзі + Допомогти з перекладом застосунку + Переклад + Авторизація виконана + Вхід на %s не підтримується + Ви вийдете з усіх джерел + Завершена + Триває + Виключити NSFW манґу з історії + Показувати номери сторінок + Включені джерела + Політика щодо знімків екрана + Дозволити + Пропонувати манґу на основі ваших уподобань + Усі дані аналізуються лише локально на цьому пристрої й ніколи нікуди не надсилаються. + Почніть читати манґу, і ви отримаєте персоналізовані пропозиції + Увімкнено + Вимкнено + Скинути фільтр + Виберіть мови, якими ви хочете читати манґу. Це можливо змінити пізніше в налаштуваннях. + Тільки по Wi-Fi + Попереднє завантаження сторінок + Ви увійшли як %s + 18+ + Різні мови + Знайти розділ + Немає розділів у цій манзі + %1$s%% + Оновлення пропозицій + Видалити вибрані елементи з пристрою назавжди\? + Видалення завершено + Сповільнення завантаження + Обробка збереженої манґи + Приховати + Доступні нові джерела манґи + Завантаження… + Очистити + Завантаження + Як в системі + Розділ відсутній + Жанри + За замовчуванням + Завжди + Продовжити + Імпорт + Натискання по краях + Налаштування сповіщень + Відкрити у веб-браузері + Недоступно + Немає доступного сховища + Нові розділи того, що ви читаєте, показано тут + Результати пошуку + Введіть пароль + Звук сповіщень + Світлодіодний індикатор + Учора + Справа наліво (←) + Створити резервну копію + Відновити з резервної копії + Всі дані були відновлені + Групувати + Сьогодні + Без звуку + Давно + Очистити всю історію оновлень назавжди\? + Деякі пристрої мають різну поведінку системи, що може порушити фонові завдання. + Видалити всі останні пошукові запити назавжди\? + Доступні джерела + Блок на NSFW + Завжди блокувати + Пропозиції + Увімкнути пропозиції + Не пропонувати NSFW манґу + Не вдалося завантажити список жанрів + Ніколи + Зовнішній вигляд + Виключити жанри + Укажіть жанри, які ви не хочете бачити в пропозиціях + Допомагає уникнути блокування вашої IP-адреси + Розділи буде видалено у фоновому режимі + Перевіряти наявність нових розділів і повідомляти про них + Ви будете отримувати повідомлення про оновлення манґи, яку ви читаєте + Увімкнути сповіщення + Ви не будете отримувати повідомлення, але нові розділи будуть відображатися у списку + Немає улюблених категорій + Назва + Змінити + Змінити категорію + Додати закладку + Видалити закладку + Закладки + Закладка видалена + Додано закладку + Відмінити + Видалено з історії + DNS через HTTPS + Режим за замовчуванням + Автоматично визначати, чи є манґа вебтуном + Автовизначення режиму читання + Вимкнути оптимізацію акумулятора + Допомагає з перевірками фонових оновлень + Щось пішло не так. Будь ласка, надішліть звіт про помилку розробникам, щоб допомогти нам її виправити. + Надіслати + Вимкнути все + Використовувати відбиток пальця, якщо доступно + Манга з Вашого улюбленого + Манга, яку Ви нещодавно читали + Недійсний домен + Звіт + Відстеження + Вийти + Заплановано + Читаю + Перечитую + Завершено + Відкладено + Занедбано + Показувати індикатори прогресу читання + Видалення даних + Показати відсоток прочитаного в історії та обраному + Манґа, позначена як NSFW, ніколи не буде додана до історії і ваш прогрес не буде збережений + Може допомогти в разі виникнення проблем. Усі авторизації будуть анульовані + Показати всі + Виберіть діапазон + Вміст не знайдено або видалено + Ваша манга буде відображатися тут + Знайдіть, що почитати у розділі «Огляд» + Назад + Введіть свою електронну пошту, щоб продовжити + Історія очищена + Керувати + Закладок ще немає + Ви можете створювати закладки під час читання манґи + Закладки видалено + Немає джерел манґи + Увімкніть джерела манґи, щоб читати онлайн + Випадкова + Ви впевнені, що бажаєте видалити вибрані улюблені категорії\? \nУсю манґу в них буде втрачено, і це неможливо скасувати. - Впорядкувати - Порожньо - Огляд - Збережена манґа - Кеш сторінок - Використання сховища - Доступні - Параметри - Режим інкогніто - Немає розділів - Автоматична прокрутка - Показувати інформаційну панель у режимі читання - Архів коміксів - Папка із зображеннями - Імпорт манґи - Імпорт завершено - Ви можете видалити оригінальний файл зі сховища, щоб заощадити місце - Імпорт почнеться незабаром - Стрічка - Розд. %1$d/%2$d Стор. %3$d/%4$d - Обліковий запис уже існує - Синхронізуйте ваші дані - Скасовано - Натисніть Назад ще раз, щоб вийти - Синхронізація - Очистити всю історію - Останні 2 години - Двічі натисніть Назад, щоб вийти зі застосунку - Підтвердження виходу - Видалено з уподобань - Інший кеш - %s - %s - Деталі помилки:<br><tt>%1$s</tt><br><br>1. Спробуйте <a href=%2$s>відкрити мангу у веб-браузері</a>, щоб переконатися, що вона доступна в джерелі<br>2. Переконайтеся, що ви використовуєте <a href=kotatsu://about>останню версію Kotatsu</a><br>3. Якщо він доступний, надішліть звіт про помилку розробникам. - Показувати ярлики останньої прочитаної манґи - Зробити нещодавно прочитану манґу доступною за довгим натисканням на іконку застосунку - Натискання на правий край або натискання правої клавіші завжди переходить на наступну сторінку - Ергономічне керування режимом читання - Яскравість - Корекція кольору - Контрастність - Скинути - Вибрані параметри кольору будуть запам\'ятовані для цієї манґи - Зберегти чи скасувати незбережені зміни\? - Скасувати - Помилка на стороні сервера (%1$d). Будь ласка спробуйте пізніше - Також очистити інформацію про нові розділи - На пристрої не залишилося вільного місця - Різні мови - Мережа недоступна - Увімкніть Wi-Fi або мобільну мережу, щоб читати манґу онлайн - Масштабування в режимі вебтуну - Відображати повзунок перемикання сторінок - Компактно - Передвчасне завантаження контенту - Джерело відключено - Позначити як актуальне - Мова - Канаде - Служби - Тут нічого нема - Щоб відстежувати прогрес читання, виберіть Меню → Відстежити на екрані деталей манги. - Міку - Аска - Міон - Рікка - Сакура - Поділиться логами - Увімкнути логування - Записувати деякі дії з метою подальшого налагодження - Мамімі - Показувати сумнівний контент - Динамічний - Колірний акцент - Показати у вигляді сітки - Дозволити нестабільні оновлення - Пропонувати оновлення до бета-версій додатку - Завантаження розпочато - Заголовок UserAgent - Перезапустіть програму, щоб застосувати зміни - Зрозумів - Ви можете вибрати один або кілька файлів .cbz або .zip, кожен файл буде розпізнано як окрема манга. - Ви можете вибрати каталог з архівами або зображеннями. Кожен архів (або підкаталог) буде розпізнано як розділ. - Швидкість - Імпортуйте раніше створену резервну копію даних користувача - Показати на полиці - Натисніть і утримуйте елемент, щоб змінити його порядок - Ви можете увійти в існуючий аккаунт, або створити новий - Знайти схожі - Параметри синхронізації - Адреса сервера - Ви можете використовувати власний сервер синхронізації або сервер за замовчуванням. Не змінюйте це, якщо ви не впевнені, що робите. - Ігноруйте помилки SSL - Виберіть дзеркало автоматично - Призупинено - Видалити завершені - Завантажувати тільки через Wi-Fi - Скасувати все - Автоматично перемикайте домени для віддалених джерел у разі помилок, якщо дзеркала доступні - Відновити - Пауза - Зупинити завантаження при переході на мобільну мережу - Увімкнути - Ні, дякую - Пропозиція: %s - Іноді показувати сповіщення з запропонованою мангою - Більше - Усі активні завантаження буде скасовано, частково завантажені дані буде втрачено - Ваша історія завантажень буде остаточно видалена - У вас немає завантажень - Завантаження відновлено - Завантаження призупинено - Завантаження видалено - Завантаження скасовано - Хочете отримувати персоналізовані пропозиції щодо манги\? - WebView недоступний: перевірте, чи встановлено провайдер WebView - Переклади - Очистити мережевий кеш - Порт - Проксі - Тип - Адреса - %1$s (%2$s) - Недійсне значення - \ No newline at end of file + Впорядкувати + Порожньо + Огляд + Збережена манґа + Кеш сторінок + Використання сховища + Доступні + Параметри + Режим інкогніто + Немає розділів + Автоматична прокрутка + Показувати інформаційну панель у режимі читання + Архів коміксів + Папка із зображеннями + Імпорт манґи + Імпорт завершено + Ви можете видалити оригінальний файл зі сховища, щоб заощадити місце + Імпорт почнеться незабаром + Стрічка + Розд. %1$d/%2$d Стор. %3$d/%4$d + Обліковий запис уже існує + Синхронізуйте ваші дані + Скасовано + Натисніть Назад ще раз, щоб вийти + Синхронізація + Очистити всю історію + Останні 2 години + Двічі натисніть Назад, щоб вийти зі застосунку + Підтвердження виходу + Видалено з уподобань + Інший кеш + %s - %s + Деталі помилки:<br><tt>%1$s</tt><br><br>1. Спробуйте <a href=%2$s>відкрити мангу у веб-браузері</a>, щоб переконатися, що вона доступна в джерелі<br>2. Переконайтеся, що ви використовуєте <a href=kotatsu://about>останню версію Kotatsu</a><br>3. Якщо він доступний, надішліть звіт про помилку розробникам. + Показувати ярлики останньої прочитаної манґи + Зробити нещодавно прочитану манґу доступною за довгим натисканням на іконку застосунку + Натискання на правий край або натискання правої клавіші завжди переходить на наступну сторінку + Ергономічне керування режимом читання + Яскравість + Корекція кольору + Контрастність + Скинути + Вибрані параметри кольору будуть запам\'ятовані для цієї манґи + Зберегти чи скасувати незбережені зміни\? + Скасувати + Помилка на стороні сервера (%1$d). Будь ласка спробуйте пізніше + Також очистити інформацію про нові розділи + На пристрої не залишилося вільного місця + Різні мови + Мережа недоступна + Увімкніть Wi-Fi або мобільну мережу, щоб читати манґу онлайн + Масштабування в режимі вебтуну + Відображати повзунок перемикання сторінок + Компактно + Передвчасне завантаження контенту + Джерело відключено + Позначити як актуальне + Мова + Канаде + Служби + Тут нічого нема + Щоб відстежувати прогрес читання, виберіть Меню → Відстежити на екрані деталей манги. + Міку + Аска + Міон + Рікка + Сакура + Поділиться логами + Увімкнути логування + Записувати деякі дії з метою подальшого налагодження + Мамімі + Показувати сумнівний контент + Динамічний + Колірний акцент + Показати у вигляді сітки + Дозволити нестабільні оновлення + Пропонувати оновлення до бета-версій додатку + Завантаження розпочато + Заголовок UserAgent + Перезапустіть програму, щоб застосувати зміни + Зрозумів + Ви можете вибрати один або кілька файлів .cbz або .zip, кожен файл буде розпізнано як окрема манга. + Ви можете вибрати каталог з архівами або зображеннями. Кожен архів (або підкаталог) буде розпізнано як розділ. + Швидкість + Імпортуйте раніше створену резервну копію даних користувача + Показати на полиці + Натисніть і утримуйте елемент, щоб змінити його порядок + Ви можете увійти в існуючий аккаунт, або створити новий + Знайти схожі + Параметри синхронізації + Адреса сервера + Ви можете використовувати власний сервер синхронізації або сервер за замовчуванням. Не змінюйте це, якщо ви не впевнені, що робите. + Ігноруйте помилки SSL + Виберіть дзеркало автоматично + Призупинено + Видалити завершені + Завантажувати тільки через Wi-Fi + Скасувати все + Автоматично перемикайте домени для віддалених джерел у разі помилок, якщо дзеркала доступні + Відновити + Пауза + Зупинити завантаження при переході на мобільну мережу + Увімкнути + Ні, дякую + Пропозиція: %s + Іноді показувати сповіщення з запропонованою мангою + Більше + Усі активні завантаження буде скасовано, частково завантажені дані буде втрачено + Ваша історія завантажень буде остаточно видалена + У вас немає завантажень + Завантаження відновлено + Завантаження призупинено + Завантаження видалено + Завантаження скасовано + Хочете отримувати персоналізовані пропозиції щодо манги\? + WebView недоступний: перевірте, чи встановлено провайдер WebView + Переклади + Очистити мережевий кеш + Порт + Проксі + Тип + Адреса + %1$s (%2$s) + Недійсне значення + diff --git a/app/src/main/res/values-vi/plurals.xml b/app/src/main/res/values-vi/plurals.xml index c2879a4fd..7b7bf3a2b 100644 --- a/app/src/main/res/values-vi/plurals.xml +++ b/app/src/main/res/values-vi/plurals.xml @@ -15,7 +15,4 @@ %1$d ngày trước - - Tổng %1$d trang - diff --git a/app/src/main/res/values-zh-rCN/plurals.xml b/app/src/main/res/values-zh-rCN/plurals.xml index a7acbeee9..dbab8c693 100644 --- a/app/src/main/res/values-zh-rCN/plurals.xml +++ b/app/src/main/res/values-zh-rCN/plurals.xml @@ -18,7 +18,4 @@ %1$d 天前 - - 共 %1$d 页 - diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 6ca5165d3..96957ff20 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1,420 +1,416 @@ - 设置 - 本地存储 - 喜欢 - 历史 - 发生了一个错误 - 网络错误 - 章节 - 列表 - 数据被恢复了,但有错误 - 正在处理… - 最新 - 评分 - 已删除所有 cookie - 所有数据都被恢复了 - 无声 - 准备… - 未找到文件 - 昨日 - 你可以创建你的历史和收藏的备份并恢复它 - 现在 - 很久以前 - - 轻点以重试 - 所选择的配置将因这部漫画而被记住 - 需要验证码 - 解决 - 今天 - 清除cookies - 有新的漫画源可用 - 根据你的喜好推荐漫画 - 所有的数据都在这个设备上进行本地分析,不会发送到任何地方。 - 从不 - 你会收到你正在阅读的漫画的更新通知 - 18+ - 各种语言 - 查找章节 - 排除流派 - 建议更新 - 检查新的章节并通知有关情况 - 详细内容 - 详细列表 - 网格 - 列表模式 - 漫画源 - 加载中… - 计算中… - %1$d/%2$d章节 - 关闭 - 再试一次 - 清除历史 - 没有发现 - 尚无历史 - 阅读 - 尚无收藏夹 - 收藏此漫画 - 新分类 - 添加 - 保存 - 分享 - 创建快捷方式… - 分享%s - 搜索 - 搜索漫画 - 正在下载… - 已下载 - 下载 - 名称 - 热门 - 更新 - 排序顺序 - 过滤器 - 主题 - 深色 - 浅色 - 跟随系统 - 页数 - 清除 - 永久清除所有阅读历史\? - 删除 - \"%s\"从本地存储中删除 - 保存页面 - 保存 - 分享图片 - 导入 - 删除 - 不支持此操作 - 选择 ZIP 或 CBZ 文件. - 无描述 - 历史和缓存 - 清除页面缓存 - B|kB|MB|GB|TB - 标准 - 条漫 - 阅读模式 - 网格大小 - 在%s上搜索 - 删除漫画 - 从设备中永久删除\"%s\"\? - 阅读器设置 - 切换页面 - 音量按钮 - 继续 - 边缘点击 - 错误 - 清除缩略图缓存 - 清除搜索历史 - 清除 - 仅限手势 - 内部存储 - 外部存储 - 范围 - 新版本应用程序已经推出 - 在网络浏览器中打开 - 这部漫画有%s.全部保存\? - 保存 - 通知 - 新章节 - 下载 - 通知设置 - 通知声音 - LED指示器 - 振动 - 收藏夹分类 - 删除 - 这里有点空… - 尝试重新表述查询。 - 你所读的内容将在这里显示 - 在侧面菜单中找到要读的内容. - 先保存内容 - 从在线来源保存或导入文件. - 书架 - 最近 - 页面动画 - 下载文件夹 - 不详 - 没有可用的存储空间 - 其他存储 - 完成 - 所有收藏夹 - 空分类 - 稍后阅读 - 更新 - 你正在阅读的新章节显示在这里 - 搜索结果 - 新版本: %s - 清除更新源 - 已清除 - 旋转屏幕 - 更新 - 源更新即将开始 - 查找更新 - 不要检查 - 输入密码 - 密码错误 - 保护应用程序 - 在启动Kotatsu时要求输入密码 - 重复密码 - 密码不匹配 - 关于 - 版本%s - 检查更新 - 没有更新 - 从右到左 - 新分类 - 缩放模式 - 适应中心 - 适应高度 - 适应宽度 - 从头开始 - 黑色 - 在AMOLED屏幕上使用更少电池 - 备份和还原 - 创建数据备份 - 从备份中恢复 - 恢复 - 清除文件 - 永久地清除所有的更新历史? - 检查新的章节 - 撤销 - 登录 - 登录后可查看此内容 - 默认值: %s - 下一页 - 输入密码以启动应用程序 - 确认 - 密码必须是4个字符或以上 - 永久地删除所有最近的搜索查询? - 欢迎 - 保存备份 - 一些设备有不同的系统行为, 这可能会破坏后台任务. - 阅读更多 - 排队 - 下载或在线阅读这缺失的章节. - 该章缺失 - 翻译此应用程序 - 翻译 - 授权 - 不支持在%s上登录 - 你将退出登录所有来源 - 类型 - 连载中 - 已完结 - 默认 - 将NSFW漫画排除在历史之外 - 页数 - 使用图源 - 现有图源 - 屏幕截图 - 允许 - 禁止18+ - 始终阻止 - 建议 - 启用建议 - 开始阅读漫画,你会得到个性化的建议 - 请勿推荐18+漫画 - 启用 - 禁用 - 无法加载流派列表 - 重置过滤器 - 查找流派 - 选择你想看的漫画的语言. 你可以在以后的设置中改变它. - 只在Wi-Fi上使用 - 总是 - 预加载页面 - 以%s身份登录 - 这部漫画中没有章节 - 外观 - 内容 - 指定您不希望在建议中看到的类型 - 从设备中永久删除所选项目\? - 删除已完成 - 下载速度减慢 - 有助于避免阻断你的IP地址 - 保存的漫画处理 - 章节将在后台被删除 - 隐藏 - 你将不会收到通知但新的章节将在列表中突出显示 - 启用通知 - 命名 - 编辑 - 编辑分类 - 没有收藏夹分类 - 添加书签 - 删除书签 - 书签 - 删除书签 - 添加书签 - 撤销 - 从历史中删除 - DNS over HTTPS - 默认模式 - 自动检测阅读器模式 - 自动检测漫画是否为条漫 - 禁用电池优化 - 帮助进行背景更新检查 - 出了点问题. 请向开发人员提交一份错误报告以帮助我们修复它. - 发送 - 全部禁用 - 计划 - 暂停 - 报告 - 追踪 - 注销 - 阅读 - 重读 - 完成 - 使用指纹 - 你喜欢的漫画 - 您最近阅读的漫画 - 在历史和收藏夹中显示阅读百分比 - 显示阅读进度指标 - 数据删除 - 标记为NSFW的漫画将永远不会被添加到历史中你的进度也不会被保存 - 可以在出现一些问题时提供帮助. 所有授权将被视为无效 - 显示全部 - 错误详情:<br><tt>%1$s</tt><br><br>1.尝试<a href=%2$s>在网络浏览器中打开漫画</a>以确保在其来源中可用<br>2. 请确保您使用的是<a href=kotatsu://about>最新版本的Kotatsu</a><br>3.如果可用,请向开发人员发送错误报告。 - 无效域名 - 此处将显示你的漫画 - 在【浏览】页面搜索想要阅读的漫画 - %1$s%% - 已取消 - 账号已存在 - 返回 - 同步 - 同步您的数据 - 输入您的邮箱以继续 - 已放弃 - 选择范围 - 清除所有历史 - 过去2小时 - 书签已移除 - 历史已清除 - 管理 - 还没有书签 - 您可以在阅读漫画时创建书签 - 无漫画源 - 启用漫画源以在线阅读漫画 - 随机 - 您确定要删除选定的收藏夹吗? + 设置 + 本地存储 + 喜欢 + 历史 + 发生了一个错误 + 网络错误 + 章节 + 列表 + 数据被恢复了,但有错误 + 正在处理… + 最新 + 评分 + 已删除所有 cookie + 所有数据都被恢复了 + 无声 + 准备… + 未找到文件 + 昨日 + 你可以创建你的历史和收藏的备份并恢复它 + 现在 + 很久以前 + + 轻点以重试 + 所选择的配置将因这部漫画而被记住 + 需要验证码 + 解决 + 今天 + 清除cookies + 有新的漫画源可用 + 根据你的喜好推荐漫画 + 所有的数据都在这个设备上进行本地分析,不会发送到任何地方。 + 从不 + 你会收到你正在阅读的漫画的更新通知 + 18+ + 各种语言 + 查找章节 + 排除流派 + 建议更新 + 检查新的章节并通知有关情况 + 详细内容 + 详细列表 + 网格 + 列表模式 + 漫画源 + 加载中… + 计算中… + %1$d/%2$d章节 + 关闭 + 再试一次 + 清除历史 + 没有发现 + 尚无历史 + 阅读 + 尚无收藏夹 + 收藏此漫画 + 新分类 + 添加 + 保存 + 分享 + 创建快捷方式… + 分享%s + 搜索 + 搜索漫画 + 正在下载… + 已下载 + 下载 + 名称 + 热门 + 更新 + 排序顺序 + 过滤器 + 主题 + 深色 + 浅色 + 跟随系统 + 页数 + 清除 + 永久清除所有阅读历史\? + 删除 + \"%s\"从本地存储中删除 + 保存页面 + 保存 + 分享图片 + 导入 + 删除 + 不支持此操作 + 选择 ZIP 或 CBZ 文件. + 无描述 + 清除页面缓存 + B|kB|MB|GB|TB + 标准 + 条漫 + 阅读模式 + 网格大小 + 在%s上搜索 + 删除漫画 + 从设备中永久删除\"%s\"\? + 阅读器设置 + 切换页面 + 音量按钮 + 继续 + 边缘点击 + 错误 + 清除缩略图缓存 + 清除搜索历史 + 清除 + 仅限手势 + 内部存储 + 外部存储 + 范围 + 新版本应用程序已经推出 + 在网络浏览器中打开 + 这部漫画有%s.全部保存\? + 保存 + 通知 + 新章节 + 下载 + 通知设置 + 通知声音 + LED指示器 + 振动 + 收藏夹分类 + 删除 + 这里有点空… + 尝试重新表述查询。 + 你所读的内容将在这里显示 + 在侧面菜单中找到要读的内容. + 先保存内容 + 从在线来源保存或导入文件. + 书架 + 最近 + 页面动画 + 下载文件夹 + 不详 + 没有可用的存储空间 + 其他存储 + 完成 + 所有收藏夹 + 空分类 + 稍后阅读 + 更新 + 你正在阅读的新章节显示在这里 + 搜索结果 + 新版本: %s + 清除更新源 + 已清除 + 旋转屏幕 + 更新 + 源更新即将开始 + 查找更新 + 不要检查 + 输入密码 + 密码错误 + 保护应用程序 + 在启动Kotatsu时要求输入密码 + 重复密码 + 密码不匹配 + 关于 + 版本%s + 检查更新 + 没有更新 + 从右到左 + 新分类 + 缩放模式 + 适应中心 + 适应高度 + 适应宽度 + 从头开始 + 黑色 + 在AMOLED屏幕上使用更少电池 + 备份和还原 + 创建数据备份 + 从备份中恢复 + 恢复 + 清除文件 + 永久地清除所有的更新历史? + 检查新的章节 + 撤销 + 登录 + 登录后可查看此内容 + 默认值: %s + 下一页 + 输入密码以启动应用程序 + 确认 + 密码必须是4个字符或以上 + 永久地删除所有最近的搜索查询? + 欢迎 + 保存备份 + 一些设备有不同的系统行为, 这可能会破坏后台任务. + 阅读更多 + 排队 + 该章缺失 + 翻译此应用程序 + 翻译 + 授权 + 不支持在%s上登录 + 你将退出登录所有来源 + 类型 + 连载中 + 已完结 + 默认 + 将NSFW漫画排除在历史之外 + 页数 + 使用图源 + 现有图源 + 屏幕截图 + 允许 + 禁止18+ + 始终阻止 + 建议 + 启用建议 + 开始阅读漫画,你会得到个性化的建议 + 请勿推荐18+漫画 + 启用 + 禁用 + 无法加载流派列表 + 重置过滤器 + 选择你想看的漫画的语言. 你可以在以后的设置中改变它. + 只在Wi-Fi上使用 + 总是 + 预加载页面 + 以%s身份登录 + 这部漫画中没有章节 + 外观 + 指定您不希望在建议中看到的类型 + 从设备中永久删除所选项目\? + 删除已完成 + 下载速度减慢 + 有助于避免阻断你的IP地址 + 保存的漫画处理 + 章节将在后台被删除 + 隐藏 + 你将不会收到通知但新的章节将在列表中突出显示 + 启用通知 + 命名 + 编辑 + 编辑分类 + 没有收藏夹分类 + 添加书签 + 删除书签 + 书签 + 删除书签 + 添加书签 + 撤销 + 从历史中删除 + DNS over HTTPS + 默认模式 + 自动检测阅读器模式 + 自动检测漫画是否为条漫 + 禁用电池优化 + 帮助进行背景更新检查 + 出了点问题. 请向开发人员提交一份错误报告以帮助我们修复它. + 发送 + 全部禁用 + 计划 + 暂停 + 报告 + 追踪 + 注销 + 阅读 + 重读 + 完成 + 使用指纹 + 你喜欢的漫画 + 您最近阅读的漫画 + 在历史和收藏夹中显示阅读百分比 + 显示阅读进度指标 + 数据删除 + 标记为NSFW的漫画将永远不会被添加到历史中你的进度也不会被保存 + 可以在出现一些问题时提供帮助. 所有授权将被视为无效 + 显示全部 + 错误详情:<br><tt>%1$s</tt><br><br>1.尝试<a href=%2$s>在网络浏览器中打开漫画</a>以确保在其来源中可用<br>2. 请确保您使用的是<a href=kotatsu://about>最新版本的Kotatsu</a><br>3.如果可用,请向开发人员发送错误报告。 + 无效域名 + 此处将显示你的漫画 + 在【浏览】页面搜索想要阅读的漫画 + %1$s%% + 已取消 + 账号已存在 + 返回 + 同步 + 同步您的数据 + 输入您的邮箱以继续 + 已放弃 + 选择范围 + 清除所有历史 + 过去2小时 + 书签已移除 + 历史已清除 + 管理 + 还没有书签 + 您可以在阅读漫画时创建书签 + 无漫画源 + 启用漫画源以在线阅读漫画 + 随机 + 您确定要删除选定的收藏夹吗? \n所有收藏夹中的漫画将丢失且无法恢复。 - 重新排序 - 留空 - 浏览 - 自动滚动 - 在阅读器中显示信息栏 - 漫画压缩包 - 图片文件夹 - 漫画导入中 - Ch. %1$d/%2$d Pg. %3$d/%4$d - %1$d 的 %2$d 启用 - 大小:%s - 再按一次返回键退出 - 按两次返回键退出应用 - 退出确认 - 已保存漫画 - 页面缓存 - 其他缓存 - 存储占用 - 可用 - 从收藏中移除 - 选项 - 隐身模式 - 无章节 - 导入完毕 - 您可以从存储中删除原文件以节省空间 - 即将开始导入 - 订阅源 - %s - %s - 内容未找到或已移除 - 点击屏幕右侧或按下右键翻到下一页 - 高效阅读器控制 - 长按应用图标显示最近阅读的漫画 - 显示最近阅读漫画的快捷方式 - 重置 - 颜色校正 - 亮度 - 对比度 - 所选颜色设置将会应用于此漫画 - 保存还是放弃未保存的更改? - 放弃 - 设备上没有剩余空间 - 显示换页滑块 - Webtoon 缩放 - 不同语言 - 网络不可用 - 打开 Wi-Fi 或移动网络在线阅读漫画 - 同样清除新章节信息 - 服务器端错误 (%1$d)。请稍后再试 - 紧凑 - 已禁用图源 - 内容预加载 - 标为当前 - 语言 - 启用日志记录 - 分享日志 - 出于调试目的记录某些操作 - 显示可疑内容 - 动态 - 颜色方案 - 用网格视图显示 - Miku - Asuka - Mion - Rikka - Sakura - 服务 - Mamimi - Kanade - 这里什么也没有 - 要跟踪阅读进度,在漫画详情屏幕上选中“菜单→ 跟踪。 - 允许不稳定更新 - 提示更新到测试版 - 已开始下载 - UserAgent 标头 - 要应用这些更改请重启程序 - 点击并长按项目排序 - 知道了 - 速度 - 导入先前创建的用户数据备份 - 在书架上显示 - 您可以选择一个或多个cbz或zip文件,每个文件都将识别为一个单独的漫画。 - 您可以选择一个包含压缩包或图片的文件夹。每个压缩包(或子文件夹)都会被识别为一个章节。 - 寻找相似 - 翻译 - WebView不可用:检查是否已安装WebView - 你可以使用自建同步服务器或默认服务器。如果你不知道自己在干什么请不要修改此处。 - 自动选择镜像 - 如果存在可用镜像,在出错时自动切换域名 - 已暂停 - 切换到移动网络时停止下载 - 移除已完成 - 取消所有 - 仅通过Wi-Fi下载 - 启用 - 不,谢谢 - 同步设定 - 服务器地址 - 暂停 - 恢复 - 忽略SSL错误 - 没有下载项 - 下载已经恢复 - 暂停下载 - 下载已被移除 - 下载被取消 - 你想要接收个人漫画推荐吗? - 推荐:%s - 偶尔显示建议漫画通知 - 更多 - 所有进行中的下载都将被取消,未下载完成的数据将丢失 - 你的下载历史将会永久删除 - 你可以登陆一个已有账号或创建新账号 - 地址 - 清除网络缓存 - 代理 - 类型 - 无效值 - \ No newline at end of file + 重新排序 + 留空 + 浏览 + 自动滚动 + 在阅读器中显示信息栏 + 漫画压缩包 + 图片文件夹 + 漫画导入中 + Ch. %1$d/%2$d Pg. %3$d/%4$d + %1$d 的 %2$d 启用 + 大小:%s + 再按一次返回键退出 + 按两次返回键退出应用 + 退出确认 + 已保存漫画 + 页面缓存 + 其他缓存 + 存储占用 + 可用 + 从收藏中移除 + 选项 + 隐身模式 + 无章节 + 导入完毕 + 您可以从存储中删除原文件以节省空间 + 即将开始导入 + 订阅源 + %s - %s + 内容未找到或已移除 + 点击屏幕右侧或按下右键翻到下一页 + 高效阅读器控制 + 长按应用图标显示最近阅读的漫画 + 显示最近阅读漫画的快捷方式 + 重置 + 颜色校正 + 亮度 + 对比度 + 所选颜色设置将会应用于此漫画 + 保存还是放弃未保存的更改? + 放弃 + 设备上没有剩余空间 + 显示换页滑块 + Webtoon 缩放 + 不同语言 + 网络不可用 + 打开 Wi-Fi 或移动网络在线阅读漫画 + 同样清除新章节信息 + 服务器端错误 (%1$d)。请稍后再试 + 紧凑 + 已禁用图源 + 内容预加载 + 标为当前 + 语言 + 启用日志记录 + 分享日志 + 出于调试目的记录某些操作 + 显示可疑内容 + 动态 + 颜色方案 + 用网格视图显示 + Miku + Asuka + Mion + Rikka + Sakura + 服务 + Mamimi + Kanade + 这里什么也没有 + 要跟踪阅读进度,在漫画详情屏幕上选中“菜单→ 跟踪。 + 允许不稳定更新 + 提示更新到测试版 + 已开始下载 + UserAgent 标头 + 要应用这些更改请重启程序 + 点击并长按项目排序 + 知道了 + 速度 + 导入先前创建的用户数据备份 + 在书架上显示 + 您可以选择一个或多个cbz或zip文件,每个文件都将识别为一个单独的漫画。 + 您可以选择一个包含压缩包或图片的文件夹。每个压缩包(或子文件夹)都会被识别为一个章节。 + 寻找相似 + 翻译 + WebView不可用:检查是否已安装WebView + 你可以使用自建同步服务器或默认服务器。如果你不知道自己在干什么请不要修改此处。 + 自动选择镜像 + 如果存在可用镜像,在出错时自动切换域名 + 已暂停 + 切换到移动网络时停止下载 + 移除已完成 + 取消所有 + 仅通过Wi-Fi下载 + 启用 + 不,谢谢 + 同步设定 + 服务器地址 + 暂停 + 恢复 + 忽略SSL错误 + 没有下载项 + 下载已经恢复 + 暂停下载 + 下载已被移除 + 下载被取消 + 你想要接收个人漫画推荐吗? + 推荐:%s + 偶尔显示建议漫画通知 + 更多 + 所有进行中的下载都将被取消,未下载完成的数据将丢失 + 你的下载历史将会永久删除 + 你可以登陆一个已有账号或创建新账号 + 地址 + 清除网络缓存 + 代理 + 类型 + 无效值 + diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 830fe30b2..f0858f20f 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1,104 +1,103 @@ - 你将不会收到通知,但新的章节将在列表中突出显示 - 计算… - 再试一次 - 尚无历史记录 - 不支持这种操作 - 在 \"探索 \"部分找到要读的内容 - 从在线来源保存或导入文件。 - 你所读的内容将在这里显示 - 在侧面菜单中找到要读的内容。 - 你的漫画将显示在这里 - 这里有点空… - 饲料更新将很快开始 - 所选择的配置将因这部漫画而被记住 - 数据被恢复了,但有错误 - 在AMOLED屏幕上使用更少的电力 - 登录后可查看此内容 - 永久地删除所有最近的搜索查询? - 永久地清除所有的更新历史? - 你将从所有来源中注销 - 從歷史中排除NSFW漫畫 - 开始阅读漫画,你会得到个性化的建议 - 根据你的喜好推荐漫画 - 指定您不希望在建议中看到的体裁 - 从设备中永久删除选定的项目? - 无法加载流派列表 - 章节将在后台被删除。这可能需要一些时间 - 检查新的章节并通知有关情况 - 有助于避免阻断你的IP地址 - 输入你的电子邮件以继续 - 有了新的漫画来源 - 自动检测漫画是否为网络漫画 - 在历史和收藏夹中显示阅读百分比 - 再次按 \"返回 \"键退出 - 本地存储 - 轻敲右边缘或按右键总是切换到下一页 - 你有未保存的修改,你想保存还是丢弃它们? - 您可以從儲存中刪除原始檔案以節省空間 - 最爱 - 章节 - 列表 - 栅格 - 设置 - 没有发现 - 选择你想看的漫画的语言。你可以在以后的设置中改变它。 - 可以在出现一些问题时提供帮助。所有授权将被视为无效 - 历史 - 发生了一个错误 - 无法连接到互联网 - 详情 - 第%1$d 。%2$d - 详细列表 - 列表模式 - 远程资源 - 正在加载… - 关闭 - 清除历史 - 所有的数据都在这个设备上进行本地分析。您的个人数据不会被转移到任何服务机构。 - 标记为NSFW的漫画将永远不会被添加到历史中,你的进度也不会被保存 - 你可以创建你的历史和收藏的备份并恢复它 - 出了点问题。请向开发人员提交一份错误报告,以帮助我们修复它。 - 所选择的颜色设置将被铭记在这部漫画中 - 要么选择ZIP或CBZ文件。 - 你可以在阅读漫画时创建书签 - 你会收到你正在阅读的漫画的更新通知 - 一些设备有不同的系统行为,这可能会破坏后台任务。 - 输入密码以启动应用程序 - 下载或在线阅读这缺失的章节。 - 在启动Kotatsu时要求输入密码 - 这部漫画中没有章节 - 你正在阅读的新章节显示在这里 - 通过长按应用程序图标来提供最近的漫画 - 这部漫画有%s 。全部保存? - 新版本的应用程序已经推出 - 密码必须是4个字符或以上 - 不支持在%s 上登录 - \"%s\" 从本地存储中删除 - 按两次 \"返回 \"键,退出应用程序 - 启用漫画来源,在线阅读漫画 - 永久清除所有阅读历史? - 从设备中永久删除 \"%s\"? - 尝试重新表述查询。 - 帮助进行背景更新检查 - 请勿推荐NSFW漫画 - 新类别 - 阅读 - 暂时没有喜欢的人 - 最喜欢这个 - 添加 - 存儲 - 分享 %s - 搜尋 - 下載中…… - 已下載 - 過濾器 - 主題 - 淺色 - 清除 - 刪除 - 分享圖片 - 刪除 - 清除頁面快取 - \ No newline at end of file + 你将不会收到通知,但新的章节将在列表中突出显示 + 计算… + 再试一次 + 尚无历史记录 + 不支持这种操作 + 在 \"探索 \"部分找到要读的内容 + 从在线来源保存或导入文件。 + 你所读的内容将在这里显示 + 在侧面菜单中找到要读的内容。 + 你的漫画将显示在这里 + 这里有点空… + 饲料更新将很快开始 + 所选择的配置将因这部漫画而被记住 + 数据被恢复了,但有错误 + 在AMOLED屏幕上使用更少的电力 + 登录后可查看此内容 + 永久地删除所有最近的搜索查询? + 永久地清除所有的更新历史? + 你将从所有来源中注销 + 從歷史中排除NSFW漫畫 + 开始阅读漫画,你会得到个性化的建议 + 根据你的喜好推荐漫画 + 指定您不希望在建议中看到的体裁 + 从设备中永久删除选定的项目? + 无法加载流派列表 + 章节将在后台被删除。这可能需要一些时间 + 检查新的章节并通知有关情况 + 有助于避免阻断你的IP地址 + 输入你的电子邮件以继续 + 有了新的漫画来源 + 自动检测漫画是否为网络漫画 + 在历史和收藏夹中显示阅读百分比 + 再次按 \"返回 \"键退出 + 本地存储 + 轻敲右边缘或按右键总是切换到下一页 + 你有未保存的修改,你想保存还是丢弃它们? + 您可以從儲存中刪除原始檔案以節省空間 + 最爱 + 章节 + 列表 + 栅格 + 设置 + 没有发现 + 选择你想看的漫画的语言。你可以在以后的设置中改变它。 + 可以在出现一些问题时提供帮助。所有授权将被视为无效 + 历史 + 发生了一个错误 + 无法连接到互联网 + 详情 + 第%1$d 。%2$d + 详细列表 + 列表模式 + 远程资源 + 正在加载… + 关闭 + 清除历史 + 所有的数据都在这个设备上进行本地分析。您的个人数据不会被转移到任何服务机构。 + 标记为NSFW的漫画将永远不会被添加到历史中,你的进度也不会被保存 + 你可以创建你的历史和收藏的备份并恢复它 + 出了点问题。请向开发人员提交一份错误报告,以帮助我们修复它。 + 所选择的颜色设置将被铭记在这部漫画中 + 要么选择ZIP或CBZ文件。 + 你可以在阅读漫画时创建书签 + 你会收到你正在阅读的漫画的更新通知 + 一些设备有不同的系统行为,这可能会破坏后台任务。 + 输入密码以启动应用程序 + 在启动Kotatsu时要求输入密码 + 这部漫画中没有章节 + 你正在阅读的新章节显示在这里 + 通过长按应用程序图标来提供最近的漫画 + 这部漫画有%s 。全部保存? + 新版本的应用程序已经推出 + 密码必须是4个字符或以上 + 不支持在%s 上登录 + \"%s\" 从本地存储中删除 + 按两次 \"返回 \"键,退出应用程序 + 启用漫画来源,在线阅读漫画 + 永久清除所有阅读历史? + 从设备中永久删除 \"%s\"? + 尝试重新表述查询。 + 帮助进行背景更新检查 + 请勿推荐NSFW漫画 + 新类别 + 阅读 + 暂时没有喜欢的人 + 最喜欢这个 + 添加 + 存儲 + 分享 %s + 搜尋 + 下載中…… + 已下載 + 過濾器 + 主題 + 淺色 + 清除 + 刪除 + 分享圖片 + 刪除 + 清除頁面快取 + diff --git a/app/src/main/res/values/plurals.xml b/app/src/main/res/values/plurals.xml index a70ca5e6a..5c87de9f0 100644 --- a/app/src/main/res/values/plurals.xml +++ b/app/src/main/res/values/plurals.xml @@ -1,9 +1,5 @@ - - Total %1$d page - Total %1$d pages - %1$d item %1$d items diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bd61d47ac..a110477a4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -62,7 +62,6 @@ This operation is not supported Either pick a ZIP or CBZ file. No description - History and cache Clear page cache B|kB|MB|GB|TB Standard @@ -187,7 +186,6 @@ Some devices have different system behavior, which may break background tasks. Read more Queued - Download or read this missing chapter online. The chapter is missing Translate this app Translation @@ -216,7 +214,6 @@ Disabled Unable to load genres list Reset filter - Find genre Select languages which you want to read manga. You can change it later in settings. Never Only on Wi-Fi @@ -229,7 +226,6 @@ No chapters in this manga %1$s%% Appearance - Content Suggestions updating Exclude genres Specify genres that you do not want to see in the suggestions diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index df869a46e..d73894979 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -2,10 +2,6 @@ - - -