From 87530f506e16db3d5c9ed89740c324ebd464117f Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 27 Aug 2023 22:05:52 -0400 Subject: [PATCH 01/59] Limit amount of updates loaded for widget Probably fixes #9868 --- .../data/updates/UpdatesRepositoryImpl.kt | 6 ++- .../sqldelight/tachiyomi/view/updatesView.sq | 3 +- .../domain/updates/interactor/GetUpdates.kt | 4 +- .../updates/repository/UpdatesRepository.kt | 4 +- .../widget/UpdatesGridGlanceWidget.kt | 37 +++++++++---------- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt index 00b4fffcf..99ec74415 100644 --- a/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt @@ -9,11 +9,12 @@ class UpdatesRepositoryImpl( private val databaseHandler: DatabaseHandler, ) : UpdatesRepository { - override suspend fun awaitWithRead(read: Boolean, after: Long): List { + override suspend fun awaitWithRead(read: Boolean, after: Long, limit: Long): List { return databaseHandler.awaitList { updatesViewQueries.getUpdatesByReadStatus( read = read, after = after, + limit = limit, mapper = updateWithRelationMapper, ) } @@ -25,11 +26,12 @@ class UpdatesRepositoryImpl( } } - override fun subscribeWithRead(read: Boolean, after: Long): Flow> { + override fun subscribeWithRead(read: Boolean, after: Long, limit: Long): Flow> { return databaseHandler.subscribeToList { updatesViewQueries.getUpdatesByReadStatus( read = read, after = after, + limit = limit, mapper = updateWithRelationMapper, ) } diff --git a/data/src/main/sqldelight/tachiyomi/view/updatesView.sq b/data/src/main/sqldelight/tachiyomi/view/updatesView.sq index 6e9fd95c2..5fdd3ea75 100644 --- a/data/src/main/sqldelight/tachiyomi/view/updatesView.sq +++ b/data/src/main/sqldelight/tachiyomi/view/updatesView.sq @@ -30,4 +30,5 @@ getUpdatesByReadStatus: SELECT * FROM updatesView WHERE read = :read -AND dateUpload > :after; \ No newline at end of file +AND dateUpload > :after +LIMIT :limit; \ No newline at end of file diff --git a/domain/src/main/java/tachiyomi/domain/updates/interactor/GetUpdates.kt b/domain/src/main/java/tachiyomi/domain/updates/interactor/GetUpdates.kt index 0c1ac5f83..b3c6481d5 100644 --- a/domain/src/main/java/tachiyomi/domain/updates/interactor/GetUpdates.kt +++ b/domain/src/main/java/tachiyomi/domain/updates/interactor/GetUpdates.kt @@ -10,7 +10,7 @@ class GetUpdates( ) { suspend fun await(read: Boolean, after: Long): List { - return repository.awaitWithRead(read, after) + return repository.awaitWithRead(read, after, limit = 500) } fun subscribe(calendar: Calendar): Flow> { @@ -18,6 +18,6 @@ class GetUpdates( } fun subscribe(read: Boolean, after: Long): Flow> { - return repository.subscribeWithRead(read, after) + return repository.subscribeWithRead(read, after, limit = 500) } } diff --git a/domain/src/main/java/tachiyomi/domain/updates/repository/UpdatesRepository.kt b/domain/src/main/java/tachiyomi/domain/updates/repository/UpdatesRepository.kt index 0856b4b9f..3b583ea90 100644 --- a/domain/src/main/java/tachiyomi/domain/updates/repository/UpdatesRepository.kt +++ b/domain/src/main/java/tachiyomi/domain/updates/repository/UpdatesRepository.kt @@ -5,9 +5,9 @@ import tachiyomi.domain.updates.model.UpdatesWithRelations interface UpdatesRepository { - suspend fun awaitWithRead(read: Boolean, after: Long): List + suspend fun awaitWithRead(read: Boolean, after: Long, limit: Long): List fun subscribeAll(after: Long, limit: Long): Flow> - fun subscribeWithRead(read: Boolean, after: Long): Flow> + fun subscribeWithRead(read: Boolean, after: Long, limit: Long): Flow> } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt index 9d7794b56..4275d08f0 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt @@ -36,14 +36,14 @@ import tachiyomi.presentation.widget.util.appWidgetBackgroundRadius import tachiyomi.presentation.widget.util.calculateRowAndColumnCount import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import uy.kohesive.injekt.injectLazy import java.util.Calendar import java.util.Date -class UpdatesGridGlanceWidget : GlanceAppWidget() { - - private val app: Application by injectLazy() - private val preferences: SecurityPreferences by injectLazy() +class UpdatesGridGlanceWidget( + private val context: Context = Injekt.get(), + private val getUpdates: GetUpdates = Injekt.get(), + private val preferences: SecurityPreferences = Injekt.get(), +) : GlanceAppWidget() { private var data: List>? = null @@ -63,23 +63,22 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() { } } - private suspend fun loadData(list: List? = null) { - withIOContext { - val manager = GlanceAppWidgetManager(app) - val ids = manager.getGlanceIds(this@UpdatesGridGlanceWidget::class.java) - if (ids.isEmpty()) return@withIOContext + private suspend fun loadData() { + val manager = GlanceAppWidgetManager(context) + val ids = manager.getGlanceIds(this@UpdatesGridGlanceWidget::class.java) + if (ids.isEmpty()) return - val processList = list - ?: Injekt.get().await( - read = false, - after = DateLimit.timeInMillis, - ) + withIOContext { + val updates = getUpdates.await( + read = false, + after = DateLimit.timeInMillis, + ) val (rowCount, columnCount) = ids .flatMap { manager.getAppWidgetSizes(it) } .maxBy { it.height.value * it.width.value } .calculateRowAndColumnCount() - data = prepareList(processList, rowCount * columnCount) + data = prepareList(updates, rowCount * columnCount) } } @@ -87,12 +86,12 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() { // Resize to cover size val widthPx = CoverWidth.value.toInt().dpToPx val heightPx = CoverHeight.value.toInt().dpToPx - val roundPx = app.resources.getDimension(R.dimen.appwidget_inner_radius) + val roundPx = context.resources.getDimension(R.dimen.appwidget_inner_radius) return processList .distinctBy { it.mangaId } .take(take) .map { updatesView -> - val request = ImageRequest.Builder(app) + val request = ImageRequest.Builder(context) .data( MangaCover( mangaId = updatesView.mangaId, @@ -114,7 +113,7 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() { } } .build() - Pair(updatesView.mangaId, app.imageLoader.executeBlocking(request).drawable?.toBitmap()) + Pair(updatesView.mangaId, context.imageLoader.executeBlocking(request).drawable?.toBitmap()) } } From 772db515934b79ef407b4213087c15035588d9ad Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 1 Sep 2023 22:47:42 -0400 Subject: [PATCH 02/59] Bump dependencies --- gradle/androidx.versions.toml | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 9fe6455c3..7be56fad6 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -27,7 +27,7 @@ guava = "com.google.guava:guava:32.1.2-android" paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging_version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } -benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-beta04" +benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-beta05" test-ext = "androidx.test.ext:junit-ktx:1.2.0-alpha01" test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-alpha01" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0-alpha04" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1cef0edeb..d9341f8be 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,7 +33,7 @@ junrar = "com.github.junrar:junrar:7.5.5" sqlite-framework = { module = "androidx.sqlite:sqlite-framework", version.ref = "sqlite" } sqlite-ktx = { module = "androidx.sqlite:sqlite-ktx", version.ref = "sqlite" } -sqlite-android = "com.github.requery:sqlite-android:3.42.0" +sqlite-android = "com.github.requery:sqlite-android:3.43.0" preferencektx = "androidx.preference:preference-ktx:1.2.1" From d29b7c4e5735dc137d578d3bcb3da1f0a02573e8 Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 1 Sep 2023 23:02:18 -0400 Subject: [PATCH 03/59] Switch to different ktlint plugin Should be better at incremental builds. To format, run `./gradlew ktlintFormat`. --- .editorconfig | 4 +- app/build.gradle.kts | 33 +++-- .../category/components/CategoryDialogs.kt | 4 +- .../history/components/HistoryDialogs.kt | 4 +- .../manga/components/MangaDialogs.kt | 2 +- .../eu/kanade/presentation/more/MoreScreen.kt | 10 +- .../{PreferenceModel.kt => Preference.kt} | 1 - .../presentation/updates/UpdatesDialog.kt | 2 +- .../source/browse/SourceFilterDialog.kt | 2 +- .../ui/manga/track/TrackInfoDialog.kt | 30 ++++- buildSrc/build.gradle.kts | 2 +- .../src/main/kotlin/tachiyomi.lint.gradle.kts | 24 ++-- core-metadata/build.gradle.kts | 1 - .../kanade/tachiyomi/network/NetworkHelper.kt | 4 +- .../tachiyomi/network/NetworkPreferences.kt | 5 +- .../tachiyomi/network/ProgressResponseBody.kt | 11 +- .../interceptor/CloudflareInterceptor.kt | 6 +- .../SpecificHostRateLimitInterceptor.kt | 11 +- .../tachiyomi/util/system/ToastExtensions.kt | 12 +- .../util/system/WebViewClientCompat.kt | 5 +- .../core/preference/AndroidPreference.kt | 18 ++- .../core/preference/AndroidPreferenceStore.kt | 6 +- .../tachiyomi/core/preference/Preference.kt | 4 +- .../core/util/lang/CoroutinesExtensions.kt | 10 +- .../java/tachiyomi/data/DatabaseAdapter.kt | 15 +-- .../tachiyomi/data/chapter/ChapterMapper.kt | 16 ++- .../data/chapter/ChapterRepositoryImpl.kt | 22 +++- .../tachiyomi/data/history/HistoryMapper.kt | 14 ++- .../java/tachiyomi/data/manga/MangaMapper.kt | 57 ++++++++- .../data/manga/MangaRepositoryImpl.kt | 16 ++- .../tachiyomi/data/release/GithubRelease.kt | 4 +- .../data/source/SourcePagingSource.kt | 4 +- .../java/tachiyomi/data/track/TrackMapper.kt | 16 ++- .../tachiyomi/data/updates/UpdatesMapper.kt | 17 ++- .../data/updates/UpdatesRepositoryImpl.kt | 12 +- .../category/interactor/ReorderCategory.kt | 6 +- .../interactor/SetSortModeForCategory.kt | 6 +- ...ings.kt => SetMangaDefaultChapterFlags.kt} | 0 .../chapter/service/ChapterRecognition.kt | 6 +- .../domain/chapter/service/ChapterSort.kt | 8 +- .../download/service/DownloadPreferences.kt | 30 ++++- .../history/interactor/GetNextChapters.kt | 6 +- .../domain/library/model/LibrarySortMode.kt | 13 +- .../library/service/LibraryPreferences.kt | 118 ++++++++++++++---- .../manga/interactor/SetFetchInterval.kt | 14 ++- .../interactor/GetApplicationRelease.kt | 19 ++- .../domain/library/model/LibraryFlagsTest.kt | 5 +- .../interactor/GetApplicationReleaseTest.kt | 8 +- gradle/libs.versions.toml | 2 +- .../macrobenchmark/StartupBenchmark.kt | 9 +- .../core/components/AdaptiveSheet.kt | 86 +++++++------ .../components/CircularProgressIndicator.kt | 4 +- .../core/components/CollapsibleBox.kt | 5 +- .../presentation/core/components/LinkIcon.kt | 7 +- .../core/components/ListGroupHeader.kt | 5 +- .../core/components/SettingsItems.kt | 48 ++----- .../core/components/VerticalFastScroller.kt | 3 +- .../core/components/material/AlertDialog.kt | 16 ++- .../core/components/material/Button.kt | 27 ++-- .../{IconButton.kt => IconButtonTokens.kt} | 0 .../components/material/NavigationRail.kt | 5 +- .../core/components/material/Scaffold.kt | 15 ++- .../core/components/material/Surface.kt | 4 +- .../core/components/material/Tabs.kt | 10 +- .../util/{Preview.kt => ThemePreviews.kt} | 0 .../widget/components/UpdatesMangaCover.kt | 5 +- .../eu/kanade/tachiyomi/source/Source.kt | 8 +- .../kanade/tachiyomi/source/model/Filter.kt | 5 +- .../tachiyomi/source/online/HttpSource.kt | 12 +- 69 files changed, 628 insertions(+), 291 deletions(-) rename app/src/main/java/eu/kanade/presentation/more/settings/{PreferenceModel.kt => Preference.kt} (99%) rename domain/src/main/java/tachiyomi/domain/chapter/interactor/{SetDefaultChapterSettings.kt => SetMangaDefaultChapterFlags.kt} (100%) rename presentation-core/src/main/java/tachiyomi/presentation/core/components/material/{IconButton.kt => IconButtonTokens.kt} (100%) rename presentation-core/src/main/java/tachiyomi/presentation/core/util/{Preview.kt => ThemePreviews.kt} (100%) diff --git a/.editorconfig b/.editorconfig index bbef1d752..d1f195728 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,5 +3,5 @@ indent_size=4 insert_final_newline=true ij_kotlin_allow_trailing_comma=true ij_kotlin_allow_trailing_comma_on_call_site=true -ij_kotlin_name_count_to_use_star_import = 2147483647 -ij_kotlin_name_count_to_use_star_import_for_members = 2147483647 \ No newline at end of file +ij_kotlin_name_count_to_use_star_import=2147483647 +ij_kotlin_name_count_to_use_star_import_for_members=2147483647 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8ccc2db65..e0658c1d8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,5 +1,4 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.jmailen.gradle.kotlinter.tasks.LintTask plugins { id("com.android.application") @@ -104,15 +103,17 @@ android { } packaging { - resources.excludes.addAll(listOf( - "META-INF/DEPENDENCIES", - "LICENSE.txt", - "META-INF/LICENSE", - "META-INF/LICENSE.txt", - "META-INF/README.md", - "META-INF/NOTICE", - "META-INF/*.kotlin_module", - )) + resources.excludes.addAll( + listOf( + "META-INF/DEPENDENCIES", + "LICENSE.txt", + "META-INF/LICENSE", + "META-INF/LICENSE.txt", + "META-INF/README.md", + "META-INF/NOTICE", + "META-INF/*.kotlin_module", + ), + ) } dependenciesInfo { @@ -264,7 +265,9 @@ androidComponents { beforeVariants { variantBuilder -> // Disables standardBenchmark if (variantBuilder.buildType == "benchmark") { - variantBuilder.enable = variantBuilder.productFlavors.containsAll(listOf("default" to "dev")) + variantBuilder.enable = variantBuilder.productFlavors.containsAll( + listOf("default" to "dev"), + ) } } onVariants(selector().withFlavor("default" to "standard")) { @@ -275,10 +278,6 @@ androidComponents { } tasks { - withType().configureEach { - exclude { it.file.path.contains("generated[\\\\/]".toRegex()) } - } - // See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers) withType { kotlinOptions.freeCompilerArgs += listOf( @@ -303,12 +302,12 @@ tasks { kotlinOptions.freeCompilerArgs += listOf( "-P", "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + - project.buildDir.absolutePath + "/compose_metrics" + project.buildDir.absolutePath + "/compose_metrics", ) kotlinOptions.freeCompilerArgs += listOf( "-P", "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + - project.buildDir.absolutePath + "/compose_metrics" + project.buildDir.absolutePath + "/compose_metrics", ) } } diff --git a/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt b/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt index ce0f59a7e..0e99d26c1 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt @@ -162,7 +162,7 @@ fun CategoryDeleteDialog( TextButton(onClick = { onDelete() onDismissRequest() - },) { + }) { Text(text = stringResource(R.string.action_ok)) } }, @@ -217,7 +217,7 @@ fun ChangeCategoryDialog( tachiyomi.presentation.core.components.material.TextButton(onClick = { onDismissRequest() onEditCategories() - },) { + }) { Text(text = stringResource(R.string.action_edit)) } Spacer(modifier = Modifier.weight(1f)) diff --git a/app/src/main/java/eu/kanade/presentation/history/components/HistoryDialogs.kt b/app/src/main/java/eu/kanade/presentation/history/components/HistoryDialogs.kt index 55cd0aac4..12db68602 100644 --- a/app/src/main/java/eu/kanade/presentation/history/components/HistoryDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/history/components/HistoryDialogs.kt @@ -61,7 +61,7 @@ fun HistoryDeleteDialog( TextButton(onClick = { onDelete(removeEverything) onDismissRequest() - },) { + }) { Text(text = stringResource(R.string.action_remove)) } }, @@ -90,7 +90,7 @@ fun HistoryDeleteAllDialog( TextButton(onClick = { onDelete() onDismissRequest() - },) { + }) { Text(text = stringResource(R.string.action_ok)) } }, diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt index 84d969247..1322adb26 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt @@ -91,7 +91,7 @@ fun SetIntervalDialog( TextButton(onClick = { onValueChanged(selectedInterval) onDismissRequest() - },) { + }) { Text(text = stringResource(R.string.action_ok)) } }, diff --git a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt index b857ace3b..076ef940d 100644 --- a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt @@ -108,11 +108,11 @@ fun MoreScreen( stringResource(R.string.paused) } else { "${stringResource(R.string.paused)} • ${ - pluralStringResource( - id = R.plurals.download_queue_summary, - count = pending, - pending, - ) + pluralStringResource( + id = R.plurals.download_queue_summary, + count = pending, + pending, + ) }" } } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceModel.kt b/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt similarity index 99% rename from app/src/main/java/eu/kanade/presentation/more/settings/PreferenceModel.kt rename to app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt index 5e8973626..fa25ff184 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceModel.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt @@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource -import eu.kanade.presentation.more.settings.Preference.PreferenceItem import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.TrackService import tachiyomi.core.preference.Preference as PreferenceData diff --git a/app/src/main/java/eu/kanade/presentation/updates/UpdatesDialog.kt b/app/src/main/java/eu/kanade/presentation/updates/UpdatesDialog.kt index 45e28127e..b5210916e 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesDialog.kt @@ -21,7 +21,7 @@ fun UpdatesDeleteConfirmationDialog( TextButton(onClick = { onConfirm() onDismissRequest() - },) { + }) { Text(text = stringResource(R.string.action_ok)) } }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt index f82f800ae..5ec0769dc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt @@ -64,7 +64,7 @@ fun SourceFilterDialog( Button(onClick = { onFilter() onDismissRequest() - },) { + }) { Text(stringResource(R.string.action_filter)) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index 47d7c5132..f92374b2a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -271,7 +271,10 @@ private data class TrackStatusSelectorScreen( selection = state.selection, onSelectionChange = sm::setSelection, selections = remember { sm.getSelections() }, - onConfirm = { sm.setStatus(); navigator.pop() }, + onConfirm = { + sm.setStatus() + navigator.pop() + }, onDismissRequest = navigator::pop, ) } @@ -322,7 +325,10 @@ private data class TrackChapterSelectorScreen( selection = state.selection, onSelectionChange = sm::setSelection, range = remember { sm.getRange() }, - onConfirm = { sm.setChapter(); navigator.pop() }, + onConfirm = { + sm.setChapter() + navigator.pop() + }, onDismissRequest = navigator::pop, ) } @@ -378,7 +384,10 @@ private data class TrackScoreSelectorScreen( selection = state.selection, onSelectionChange = sm::setSelection, selections = remember { sm.getSelections() }, - onConfirm = { sm.setScore(); navigator.pop() }, + onConfirm = { + sm.setScore() + navigator.pop() + }, onDismissRequest = navigator::pop, ) } @@ -495,7 +504,10 @@ private data class TrackDateSelectorScreen( }, initialSelectedDateMillis = sm.initialSelection, selectableDates = selectableDates, - onConfirm = { sm.setDate(it); navigator.pop() }, + onConfirm = { + sm.setDate(it) + navigator.pop() + }, onRemove = { sm.confirmRemoveDate(navigator) }.takeIf { canRemove }, onDismissRequest = navigator::pop, ) @@ -584,7 +596,10 @@ private data class TrackDateRemoverScreen( Text(text = stringResource(android.R.string.cancel)) } FilledTonalButton( - onClick = { sm.removeDate(); navigator.popUntil { it is TrackInfoDialogHomeScreen } }, + onClick = { + sm.removeDate() + navigator.popUntil { it is TrackInfoDialogHomeScreen } + }, colors = ButtonDefaults.filledTonalButtonColors( containerColor = MaterialTheme.colorScheme.errorContainer, contentColor = MaterialTheme.colorScheme.onErrorContainer, @@ -646,7 +661,10 @@ data class TrackServiceSearchScreen( queryResult = state.queryResult, selected = state.selected, onSelectedChange = sm::updateSelection, - onConfirmSelection = { sm.registerTracking(state.selected!!); navigator.pop() }, + onConfirmSelection = { + sm.registerTracking(state.selected!!) + navigator.pop() + }, onDismissRequest = navigator::pop, ) } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b5854fcb5..2c76035b7 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -5,7 +5,7 @@ plugins { dependencies { implementation(androidxLibs.gradle) implementation(kotlinLibs.gradle) - implementation(libs.kotlinter) + implementation(libs.ktlint) implementation(gradleApi()) } diff --git a/buildSrc/src/main/kotlin/tachiyomi.lint.gradle.kts b/buildSrc/src/main/kotlin/tachiyomi.lint.gradle.kts index 12b7b2295..a89d88592 100644 --- a/buildSrc/src/main/kotlin/tachiyomi.lint.gradle.kts +++ b/buildSrc/src/main/kotlin/tachiyomi.lint.gradle.kts @@ -1,20 +1,14 @@ -import org.jmailen.gradle.kotlinter.KotlinterExtension -import org.jmailen.gradle.kotlinter.KotlinterPlugin +import org.jlleitschuh.gradle.ktlint.KtlintExtension +import org.jlleitschuh.gradle.ktlint.KtlintPlugin -apply() +apply() -extensions.configure("kotlinter") { - experimentalRules = true +extensions.configure("ktlint") { + version.set("0.50.0") + android.set(true) + enableExperimentalRules.set(true) - disabledRules = arrayOf( - "experimental:argument-list-wrapping", // Doesn't play well with Android Studio - "filename", // Often broken to give a more general name - ) -} - -tasks { - named("preBuild").configure { - if (!System.getenv("CI").toBoolean()) - dependsOn("formatKotlin") + filter { + exclude("**/generated/**") } } diff --git a/core-metadata/build.gradle.kts b/core-metadata/build.gradle.kts index 51db46b91..43b8846ab 100644 --- a/core-metadata/build.gradle.kts +++ b/core-metadata/build.gradle.kts @@ -11,7 +11,6 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-rules.pro") } - } dependencies { diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt index 38ba749d2..6893a0495 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -39,7 +39,9 @@ class NetworkHelper( builder.addNetworkInterceptor(httpLoggingInterceptor) } - builder.addInterceptor(CloudflareInterceptor(context, cookieJar, ::defaultUserAgentProvider)) + builder.addInterceptor( + CloudflareInterceptor(context, cookieJar, ::defaultUserAgentProvider), + ) when (preferences.dohProvider().get()) { PREF_DOH_CLOUDFLARE -> builder.dohCloudflare() diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt index 5e14d0342..cba50e99c 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt @@ -17,6 +17,9 @@ class NetworkPreferences( } fun defaultUserAgent(): Preference { - return preferenceStore.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0") + return preferenceStore.getString( + "default_user_agent", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0", + ) } } diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt b/core/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt index 72248f17b..6ba53b197 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt @@ -9,7 +9,10 @@ import okio.Source import okio.buffer import java.io.IOException -class ProgressResponseBody(private val responseBody: ResponseBody, private val progressListener: ProgressListener) : ResponseBody() { +class ProgressResponseBody( + private val responseBody: ResponseBody, + private val progressListener: ProgressListener, +) : ResponseBody() { private val bufferedSource: BufferedSource by lazy { source(responseBody.source()).buffer() @@ -36,7 +39,11 @@ class ProgressResponseBody(private val responseBody: ResponseBody, private val p val bytesRead = super.read(sink, byteCount) // read() returns the number of bytes read, or -1 if this source is exhausted. totalBytesRead += if (bytesRead != -1L) bytesRead else 0 - progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1L) + progressListener.update( + totalBytesRead, + responseBody.contentLength(), + bytesRead == -1L, + ) return bytesRead } } diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt b/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt index 25b5a140a..d5893bb05 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt @@ -31,7 +31,11 @@ class CloudflareInterceptor( return response.code in ERROR_CODES && response.header("Server") in SERVER_CHECK } - override fun intercept(chain: Interceptor.Chain, request: Request, response: Response): Response { + override fun intercept( + chain: Interceptor.Chain, + request: Request, + response: Response, + ): Response { try { response.close() cookieManager.remove(request.url, COOKIE_NAMES, 0) diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt b/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt index b364db743..c86f780d9 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt @@ -33,7 +33,9 @@ fun OkHttpClient.Builder.rateLimitHost( permits: Int, period: Long = 1, unit: TimeUnit = TimeUnit.SECONDS, -) = addInterceptor(RateLimitInterceptor(httpUrl.host, permits, period.toDuration(unit.toDurationUnit()))) +) = addInterceptor( + RateLimitInterceptor(httpUrl.host, permits, period.toDuration(unit.toDurationUnit())), +) /** * An OkHttp interceptor that handles given url host's rate limiting. @@ -69,8 +71,5 @@ fun OkHttpClient.Builder.rateLimitHost( * @param permits [Int] Number of requests allowed within a period of units. * @param period [Duration] The limiting duration. Defaults to 1.seconds. */ -fun OkHttpClient.Builder.rateLimitHost( - url: String, - permits: Int, - period: Duration = 1.seconds, -) = addInterceptor(RateLimitInterceptor(url.toHttpUrlOrNull()?.host, permits, period)) +fun OkHttpClient.Builder.rateLimitHost(url: String, permits: Int, period: Duration = 1.seconds) = + addInterceptor(RateLimitInterceptor(url.toHttpUrlOrNull()?.host, permits, period)) diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/system/ToastExtensions.kt b/core/src/main/java/eu/kanade/tachiyomi/util/system/ToastExtensions.kt index 4901e7463..9e4554cb4 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/system/ToastExtensions.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/system/ToastExtensions.kt @@ -10,7 +10,11 @@ import androidx.annotation.StringRes * @param resource the text resource. * @param duration the duration of the toast. Defaults to short. */ -fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast { +fun Context.toast( + @StringRes resource: Int, + duration: Int = Toast.LENGTH_SHORT, + block: (Toast) -> Unit = {}, +): Toast { return toast(getString(resource), duration, block) } @@ -20,7 +24,11 @@ fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT, * @param text the text to display. * @param duration the duration of the toast. Defaults to short. */ -fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast { +fun Context.toast( + text: String?, + duration: Int = Toast.LENGTH_SHORT, + block: (Toast) -> Unit = {}, +): Toast { return Toast.makeText(applicationContext, text.orEmpty(), duration).also { block(it) it.show() diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt index 6c6fba4ff..93ce0337d 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt @@ -47,10 +47,7 @@ abstract class WebViewClientCompat : WebViewClient() { return shouldInterceptRequestCompat(view, request.url.toString()) } - final override fun shouldInterceptRequest( - view: WebView, - url: String, - ): WebResourceResponse? { + final override fun shouldInterceptRequest(view: WebView, url: String): WebResourceResponse? { return shouldInterceptRequestCompat(view, url) } diff --git a/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt b/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt index 00f3701d0..a0f2f335c 100644 --- a/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt +++ b/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt @@ -68,7 +68,11 @@ sealed class AndroidPreference( key: String, defaultValue: String, ) : AndroidPreference(preferences, keyFlow, key, defaultValue) { - override fun read(preferences: SharedPreferences, key: String, defaultValue: String): String { + override fun read( + preferences: SharedPreferences, + key: String, + defaultValue: String, + ): String { return preferences.getString(key, defaultValue) ?: defaultValue } @@ -128,7 +132,11 @@ sealed class AndroidPreference( key: String, defaultValue: Boolean, ) : AndroidPreference(preferences, keyFlow, key, defaultValue) { - override fun read(preferences: SharedPreferences, key: String, defaultValue: Boolean): Boolean { + override fun read( + preferences: SharedPreferences, + key: String, + defaultValue: Boolean, + ): Boolean { return preferences.getBoolean(key, defaultValue) } @@ -143,7 +151,11 @@ sealed class AndroidPreference( key: String, defaultValue: Set, ) : AndroidPreference>(preferences, keyFlow, key, defaultValue) { - override fun read(preferences: SharedPreferences, key: String, defaultValue: Set): Set { + override fun read( + preferences: SharedPreferences, + key: String, + defaultValue: Set, + ): Set { return preferences.getStringSet(key, defaultValue) ?: defaultValue } diff --git a/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt b/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt index 74c2872d8..c59652da5 100644 --- a/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt +++ b/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt @@ -64,7 +64,11 @@ class AndroidPreferenceStore( private val SharedPreferences.keyFlow get() = callbackFlow { - val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key: String? -> trySend(key) } + val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key: String? -> + trySend( + key, + ) + } registerOnSharedPreferenceChangeListener(listener) awaitClose { unregisterOnSharedPreferenceChangeListener(listener) diff --git a/core/src/main/java/tachiyomi/core/preference/Preference.kt b/core/src/main/java/tachiyomi/core/preference/Preference.kt index 67b7a44f4..e76ea23d4 100644 --- a/core/src/main/java/tachiyomi/core/preference/Preference.kt +++ b/core/src/main/java/tachiyomi/core/preference/Preference.kt @@ -23,7 +23,9 @@ interface Preference { fun stateIn(scope: CoroutineScope): StateFlow } -inline fun Preference.getAndSet(crossinline block: (T) -> R) = set(block(get())) +inline fun Preference.getAndSet(crossinline block: (T) -> R) = set( + block(get()), +) operator fun Preference>.plusAssign(item: T) { set(get() + item) diff --git a/core/src/main/java/tachiyomi/core/util/lang/CoroutinesExtensions.kt b/core/src/main/java/tachiyomi/core/util/lang/CoroutinesExtensions.kt index 4573b2d85..829207a9b 100644 --- a/core/src/main/java/tachiyomi/core/util/lang/CoroutinesExtensions.kt +++ b/core/src/main/java/tachiyomi/core/util/lang/CoroutinesExtensions.kt @@ -52,9 +52,15 @@ fun CoroutineScope.launchIO(block: suspend CoroutineScope.() -> Unit): Job = fun CoroutineScope.launchNonCancellable(block: suspend CoroutineScope.() -> Unit): Job = launchIO { withContext(NonCancellable, block) } -suspend fun withUIContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.Main, block) +suspend fun withUIContext(block: suspend CoroutineScope.() -> T) = withContext( + Dispatchers.Main, + block, +) -suspend fun withIOContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.IO, block) +suspend fun withIOContext(block: suspend CoroutineScope.() -> T) = withContext( + Dispatchers.IO, + block, +) suspend fun withNonCancellableContext(block: suspend CoroutineScope.() -> T) = withContext(NonCancellable, block) diff --git a/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt b/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt index 4a3475b4f..596a31286 100644 --- a/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt +++ b/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt @@ -11,13 +11,14 @@ object DateColumnAdapter : ColumnAdapter { private const val LIST_OF_STRINGS_SEPARATOR = ", " object StringListColumnAdapter : ColumnAdapter, String> { - override fun decode(databaseValue: String) = - if (databaseValue.isEmpty()) { - emptyList() - } else { - databaseValue.split(LIST_OF_STRINGS_SEPARATOR) - } - override fun encode(value: List) = value.joinToString(separator = LIST_OF_STRINGS_SEPARATOR) + override fun decode(databaseValue: String) = if (databaseValue.isEmpty()) { + emptyList() + } else { + databaseValue.split(LIST_OF_STRINGS_SEPARATOR) + } + override fun encode(value: List) = value.joinToString( + separator = LIST_OF_STRINGS_SEPARATOR, + ) } object UpdateStrategyColumnAdapter : ColumnAdapter { diff --git a/data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt b/data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt index 71ae1720e..c8243682f 100644 --- a/data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt +++ b/data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt @@ -2,7 +2,21 @@ package tachiyomi.data.chapter import tachiyomi.domain.chapter.model.Chapter -val chapterMapper: (Long, Long, String, String, String?, Boolean, Boolean, Long, Double, Long, Long, Long, Long) -> Chapter = +val chapterMapper: ( + Long, + Long, + String, + String, + String?, + Boolean, + Boolean, + Long, + Double, + Long, + Long, + Long, + Long, +) -> Chapter = { id, mangaId, url, name, scanlator, read, bookmark, lastPageRead, chapterNumber, sourceOrder, dateFetch, dateUpload, lastModifiedAt -> Chapter( id = id, diff --git a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt index 45a61e363..594a592ac 100644 --- a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt @@ -81,7 +81,12 @@ class ChapterRepositoryImpl( } override suspend fun getBookmarkedChaptersByMangaId(mangaId: Long): List { - return handler.awaitList { chaptersQueries.getBookmarkedChaptersByMangaId(mangaId, chapterMapper) } + return handler.awaitList { + chaptersQueries.getBookmarkedChaptersByMangaId( + mangaId, + chapterMapper, + ) + } } override suspend fun getChapterById(id: Long): Chapter? { @@ -89,10 +94,21 @@ class ChapterRepositoryImpl( } override suspend fun getChapterByMangaIdAsFlow(mangaId: Long): Flow> { - return handler.subscribeToList { chaptersQueries.getChaptersByMangaId(mangaId, chapterMapper) } + return handler.subscribeToList { + chaptersQueries.getChaptersByMangaId( + mangaId, + chapterMapper, + ) + } } override suspend fun getChapterByUrlAndMangaId(url: String, mangaId: Long): Chapter? { - return handler.awaitOneOrNull { chaptersQueries.getChapterByUrlAndMangaId(url, mangaId, chapterMapper) } + return handler.awaitOneOrNull { + chaptersQueries.getChapterByUrlAndMangaId( + url, + mangaId, + chapterMapper, + ) + } } } diff --git a/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt b/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt index c2d110f74..134a1c91c 100644 --- a/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt +++ b/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt @@ -14,7 +14,19 @@ val historyMapper: (Long, Long, Date?, Long) -> History = { id, chapterId, readA ) } -val historyWithRelationsMapper: (Long, Long, Long, String, String?, Long, Boolean, Long, Double, Date?, Long) -> HistoryWithRelations = { +val historyWithRelationsMapper: ( + Long, + Long, + Long, + String, + String?, + Long, + Boolean, + Long, + Double, + Date?, + Long, +) -> HistoryWithRelations = { historyId, mangaId, chapterId, title, thumbnailUrl, sourceId, isFavorite, coverLastModified, chapterNumber, readAt, readDuration -> HistoryWithRelations( id = historyId, diff --git a/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt b/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt index 3cc46aa5c..43bb1ed0c 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt @@ -4,7 +4,30 @@ import eu.kanade.tachiyomi.source.model.UpdateStrategy import tachiyomi.domain.library.model.LibraryManga import tachiyomi.domain.manga.model.Manga -val mangaMapper: (Long, Long, String, String?, String?, String?, List?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long?) -> Manga = +val mangaMapper: ( + Long, + Long, + String, + String?, + String?, + String?, + List?, + String, + Long, + String?, + Boolean, + Long?, + Long?, + Boolean, + Long, + Long, + Long, + Long, + UpdateStrategy, + Long, + Long, + Long?, +) -> Manga = { id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt -> Manga( id = id, @@ -32,7 +55,37 @@ val mangaMapper: (Long, Long, String, String?, String?, String?, List?, ) } -val libraryManga: (Long, Long, String, String?, String?, String?, List?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long?, Long, Double, Long, Long, Long, Double, Long) -> LibraryManga = +val libraryManga: ( + Long, + Long, + String, + String?, + String?, + String?, + List?, + String, + Long, + String?, + Boolean, + Long?, + Long?, + Boolean, + Long, + Long, + Long, + Long, + UpdateStrategy, + Long, + Long, + Long?, + Long, + Double, + Long, + Long, + Long, + Double, + Long, +) -> LibraryManga = { id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt, totalCount, readCount, latestUpload, chapterFetchedAt, lastRead, bookmarkCount, category -> LibraryManga( manga = mangaMapper( diff --git a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt index 49f3160a6..39bbcb99f 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt @@ -24,11 +24,23 @@ class MangaRepositoryImpl( } override suspend fun getMangaByUrlAndSourceId(url: String, sourceId: Long): Manga? { - return handler.awaitOneOrNull(inTransaction = true) { mangasQueries.getMangaByUrlAndSource(url, sourceId, mangaMapper) } + return handler.awaitOneOrNull(inTransaction = true) { + mangasQueries.getMangaByUrlAndSource( + url, + sourceId, + mangaMapper, + ) + } } override fun getMangaByUrlAndSourceIdAsFlow(url: String, sourceId: Long): Flow { - return handler.subscribeToOneOrNull { mangasQueries.getMangaByUrlAndSource(url, sourceId, mangaMapper) } + return handler.subscribeToOneOrNull { + mangasQueries.getMangaByUrlAndSource( + url, + sourceId, + mangaMapper, + ) + } } override suspend fun getFavorites(): List { diff --git a/data/src/main/java/tachiyomi/data/release/GithubRelease.kt b/data/src/main/java/tachiyomi/data/release/GithubRelease.kt index 94394cef0..f7fa16923 100644 --- a/data/src/main/java/tachiyomi/data/release/GithubRelease.kt +++ b/data/src/main/java/tachiyomi/data/release/GithubRelease.kt @@ -32,7 +32,9 @@ data class GitHubAssets(@SerialName("browser_download_url") val downloadLink: St * Reference: https://stackoverflow.com/a/30281147 */ val gitHubUsernameMentionRegex = - """\B@([a-z0-9](?:-(?=[a-z0-9])|[a-z0-9]){0,38}(?<=[a-z0-9]))""".toRegex(RegexOption.IGNORE_CASE) + """\B@([a-z0-9](?:-(?=[a-z0-9])|[a-z0-9]){0,38}(?<=[a-z0-9]))""".toRegex( + RegexOption.IGNORE_CASE, + ) val releaseMapper: (GithubRelease) -> Release = { Release( diff --git a/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt b/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt index 032ae0ab5..e8295a258 100644 --- a/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt +++ b/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt @@ -9,7 +9,9 @@ import tachiyomi.core.util.lang.awaitSingle import tachiyomi.core.util.lang.withIOContext import tachiyomi.domain.source.repository.SourcePagingSourceType -class SourceSearchPagingSource(source: CatalogueSource, val query: String, val filters: FilterList) : SourcePagingSource(source) { +class SourceSearchPagingSource(source: CatalogueSource, val query: String, val filters: FilterList) : SourcePagingSource( + source, +) { override suspend fun requestNextPage(currentPage: Int): MangasPage { return source.fetchSearchManga(currentPage, query, filters).awaitSingle() } diff --git a/data/src/main/java/tachiyomi/data/track/TrackMapper.kt b/data/src/main/java/tachiyomi/data/track/TrackMapper.kt index e8978e25b..a4a9714f6 100644 --- a/data/src/main/java/tachiyomi/data/track/TrackMapper.kt +++ b/data/src/main/java/tachiyomi/data/track/TrackMapper.kt @@ -2,7 +2,21 @@ package tachiyomi.data.track import tachiyomi.domain.track.model.Track -val trackMapper: (Long, Long, Long, Long, Long?, String, Double, Long, Long, Double, String, Long, Long) -> Track = +val trackMapper: ( + Long, + Long, + Long, + Long, + Long?, + String, + Double, + Long, + Long, + Double, + String, + Long, + Long, +) -> Track = { id, mangaId, syncId, remoteId, libraryId, title, lastChapterRead, totalChapters, status, score, remoteUrl, startDate, finishDate -> Track( id = id, diff --git a/data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt b/data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt index efbc55410..56e9743a9 100644 --- a/data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt +++ b/data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt @@ -3,7 +3,22 @@ package tachiyomi.data.updates import tachiyomi.domain.manga.model.MangaCover import tachiyomi.domain.updates.model.UpdatesWithRelations -val updateWithRelationMapper: (Long, String, Long, String, String?, Boolean, Boolean, Long, Long, Boolean, String?, Long, Long, Long) -> UpdatesWithRelations = { +val updateWithRelationMapper: ( + Long, + String, + Long, + String, + String?, + Boolean, + Boolean, + Long, + Long, + Boolean, + String?, + Long, + Long, + Long, +) -> UpdatesWithRelations = { mangaId, mangaTitle, chapterId, chapterName, scanlator, read, bookmark, lastPageRead, sourceId, favorite, thumbnailUrl, coverLastModified, _, dateFetch -> UpdatesWithRelations( mangaId = mangaId, diff --git a/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt index 99ec74415..b50aee4be 100644 --- a/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt @@ -9,7 +9,11 @@ class UpdatesRepositoryImpl( private val databaseHandler: DatabaseHandler, ) : UpdatesRepository { - override suspend fun awaitWithRead(read: Boolean, after: Long, limit: Long): List { + override suspend fun awaitWithRead( + read: Boolean, + after: Long, + limit: Long, + ): List { return databaseHandler.awaitList { updatesViewQueries.getUpdatesByReadStatus( read = read, @@ -26,7 +30,11 @@ class UpdatesRepositoryImpl( } } - override fun subscribeWithRead(read: Boolean, after: Long, limit: Long): Flow> { + override fun subscribeWithRead( + read: Boolean, + after: Long, + limit: Long, + ): Flow> { return databaseHandler.subscribeToList { updatesViewQueries.getUpdatesByReadStatus( read = read, diff --git a/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt b/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt index af61400ab..b29cfd093 100644 --- a/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt +++ b/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt @@ -16,11 +16,9 @@ class ReorderCategory( private val mutex = Mutex() - suspend fun moveUp(category: Category): Result = - await(category, MoveTo.UP) + suspend fun moveUp(category: Category): Result = await(category, MoveTo.UP) - suspend fun moveDown(category: Category): Result = - await(category, MoveTo.DOWN) + suspend fun moveDown(category: Category): Result = await(category, MoveTo.DOWN) private suspend fun await(category: Category, moveTo: MoveTo) = withNonCancellableContext { mutex.withLock { diff --git a/domain/src/main/java/tachiyomi/domain/category/interactor/SetSortModeForCategory.kt b/domain/src/main/java/tachiyomi/domain/category/interactor/SetSortModeForCategory.kt index 28c999e9f..e514e0898 100644 --- a/domain/src/main/java/tachiyomi/domain/category/interactor/SetSortModeForCategory.kt +++ b/domain/src/main/java/tachiyomi/domain/category/interactor/SetSortModeForCategory.kt @@ -28,7 +28,11 @@ class SetSortModeForCategory( } } - suspend fun await(category: Category?, type: LibrarySort.Type, direction: LibrarySort.Direction) { + suspend fun await( + category: Category?, + type: LibrarySort.Type, + direction: LibrarySort.Direction, + ) { await(category?.id, type, direction) } } diff --git a/domain/src/main/java/tachiyomi/domain/chapter/interactor/SetDefaultChapterSettings.kt b/domain/src/main/java/tachiyomi/domain/chapter/interactor/SetMangaDefaultChapterFlags.kt similarity index 100% rename from domain/src/main/java/tachiyomi/domain/chapter/interactor/SetDefaultChapterSettings.kt rename to domain/src/main/java/tachiyomi/domain/chapter/interactor/SetMangaDefaultChapterFlags.kt diff --git a/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt b/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt index d41eb1484..b2c3f6b44 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt @@ -30,7 +30,11 @@ object ChapterRecognition { */ private val unwantedWhiteSpace = Regex("""\s(?=extra|special|omake)""") - fun parseChapterNumber(mangaTitle: String, chapterName: String, chapterNumber: Double? = null): Double { + fun parseChapterNumber( + mangaTitle: String, + chapterName: String, + chapterNumber: Double? = null, + ): Double { // If chapter number is known return. if (chapterNumber != null && (chapterNumber == -2.0 || chapterNumber > -1.0)) { return chapterNumber diff --git a/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterSort.kt b/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterSort.kt index e7f5648cb..45f302455 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterSort.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterSort.kt @@ -3,7 +3,13 @@ package tachiyomi.domain.chapter.service import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.model.Manga -fun getChapterSort(manga: Manga, sortDescending: Boolean = manga.sortDescending()): (Chapter, Chapter) -> Int { +fun getChapterSort( + manga: Manga, + sortDescending: Boolean = manga.sortDescending(), +): ( + Chapter, + Chapter, +) -> Int { return when (manga.sorting) { Manga.CHAPTER_SORTING_SOURCE -> when (sortDescending) { true -> { c1, c2 -> c1.sourceOrder.compareTo(c2.sourceOrder) } diff --git a/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt b/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt index cc930cf51..51a07dc8e 100644 --- a/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt @@ -8,9 +8,15 @@ class DownloadPreferences( private val preferenceStore: PreferenceStore, ) { - fun downloadsDirectory() = preferenceStore.getString("download_directory", folderProvider.path()) + fun downloadsDirectory() = preferenceStore.getString( + "download_directory", + folderProvider.path(), + ) - fun downloadOnlyOverWifi() = preferenceStore.getBoolean("pref_download_only_over_wifi_key", true) + fun downloadOnlyOverWifi() = preferenceStore.getBoolean( + "pref_download_only_over_wifi_key", + true, + ) fun saveChaptersAsCBZ() = preferenceStore.getBoolean("save_chapter_as_cbz", true) @@ -20,15 +26,27 @@ class DownloadPreferences( fun removeAfterReadSlots() = preferenceStore.getInt("remove_after_read_slots", -1) - fun removeAfterMarkedAsRead() = preferenceStore.getBoolean("pref_remove_after_marked_as_read_key", false) + fun removeAfterMarkedAsRead() = preferenceStore.getBoolean( + "pref_remove_after_marked_as_read_key", + false, + ) fun removeBookmarkedChapters() = preferenceStore.getBoolean("pref_remove_bookmarked", false) - fun removeExcludeCategories() = preferenceStore.getStringSet("remove_exclude_categories", emptySet()) + fun removeExcludeCategories() = preferenceStore.getStringSet( + "remove_exclude_categories", + emptySet(), + ) fun downloadNewChapters() = preferenceStore.getBoolean("download_new", false) - fun downloadNewChapterCategories() = preferenceStore.getStringSet("download_new_categories", emptySet()) + fun downloadNewChapterCategories() = preferenceStore.getStringSet( + "download_new_categories", + emptySet(), + ) - fun downloadNewChapterCategoriesExclude() = preferenceStore.getStringSet("download_new_categories_exclude", emptySet()) + fun downloadNewChapterCategoriesExclude() = preferenceStore.getStringSet( + "download_new_categories_exclude", + emptySet(), + ) } diff --git a/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt b/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt index ebe6fa83e..6e9526158 100644 --- a/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt +++ b/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt @@ -30,7 +30,11 @@ class GetNextChapters( } } - suspend fun await(mangaId: Long, fromChapterId: Long, onlyUnread: Boolean = true): List { + suspend fun await( + mangaId: Long, + fromChapterId: Long, + onlyUnread: Boolean = true, + ): List { val chapters = await(mangaId, onlyUnread) val currChapterIndex = chapters.indexOfFirst { it.id == fromChapterId } val nextChapters = chapters.subList(max(0, currChapterIndex), chapters.size) diff --git a/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt b/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt index 40acc5b5a..7f525eb57 100644 --- a/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt +++ b/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt @@ -65,7 +65,18 @@ data class LibrarySort( } companion object { - val types by lazy { setOf(Type.Alphabetical, Type.LastRead, Type.LastUpdate, Type.UnreadCount, Type.TotalChapters, Type.LatestChapter, Type.ChapterFetchDate, Type.DateAdded) } + val types by lazy { + setOf( + Type.Alphabetical, + Type.LastRead, + Type.LastUpdate, + Type.UnreadCount, + Type.TotalChapters, + Type.LatestChapter, + Type.ChapterFetchDate, + Type.DateAdded, + ) + } val directions by lazy { setOf(Direction.Ascending, Direction.Descending) } val default = LibrarySort(Type.Alphabetical, Direction.Ascending) diff --git a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt index e66c705d9..8c853c759 100644 --- a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt @@ -11,9 +11,19 @@ class LibraryPreferences( private val preferenceStore: PreferenceStore, ) { - fun displayMode() = preferenceStore.getObject("pref_display_mode_library", LibraryDisplayMode.default, LibraryDisplayMode.Serializer::serialize, LibraryDisplayMode.Serializer::deserialize) + fun displayMode() = preferenceStore.getObject( + "pref_display_mode_library", + LibraryDisplayMode.default, + LibraryDisplayMode.Serializer::serialize, + LibraryDisplayMode.Serializer::deserialize, + ) - fun sortingMode() = preferenceStore.getObject("library_sorting_mode", LibrarySort.default, LibrarySort.Serializer::serialize, LibrarySort.Serializer::deserialize) + fun sortingMode() = preferenceStore.getObject( + "library_sorting_mode", + LibrarySort.default, + LibrarySort.Serializer::serialize, + LibrarySort.Serializer::deserialize, + ) fun portraitColumns() = preferenceStore.getInt("pref_library_columns_portrait_key", 0) @@ -42,31 +52,64 @@ class LibraryPreferences( fun autoUpdateTrackers() = preferenceStore.getBoolean("auto_update_trackers", false) - fun showContinueReadingButton() = preferenceStore.getBoolean("display_continue_reading_button", false) + fun showContinueReadingButton() = preferenceStore.getBoolean( + "display_continue_reading_button", + false, + ) // region Filter - fun filterDownloaded() = preferenceStore.getEnum("pref_filter_library_downloaded_v2", TriState.DISABLED) + fun filterDownloaded() = preferenceStore.getEnum( + "pref_filter_library_downloaded_v2", + TriState.DISABLED, + ) fun filterUnread() = preferenceStore.getEnum("pref_filter_library_unread_v2", TriState.DISABLED) - fun filterStarted() = preferenceStore.getEnum("pref_filter_library_started_v2", TriState.DISABLED) + fun filterStarted() = preferenceStore.getEnum( + "pref_filter_library_started_v2", + TriState.DISABLED, + ) - fun filterBookmarked() = preferenceStore.getEnum("pref_filter_library_bookmarked_v2", TriState.DISABLED) + fun filterBookmarked() = preferenceStore.getEnum( + "pref_filter_library_bookmarked_v2", + TriState.DISABLED, + ) - fun filterCompleted() = preferenceStore.getEnum("pref_filter_library_completed_v2", TriState.DISABLED) + fun filterCompleted() = preferenceStore.getEnum( + "pref_filter_library_completed_v2", + TriState.DISABLED, + ) - fun filterIntervalCustom() = preferenceStore.getEnum("pref_filter_library_interval_custom", TriState.DISABLED) + fun filterIntervalCustom() = preferenceStore.getEnum( + "pref_filter_library_interval_custom", + TriState.DISABLED, + ) - fun filterIntervalLong() = preferenceStore.getEnum("pref_filter_library_interval_long", TriState.DISABLED) + fun filterIntervalLong() = preferenceStore.getEnum( + "pref_filter_library_interval_long", + TriState.DISABLED, + ) - fun filterIntervalLate() = preferenceStore.getEnum("pref_filter_library_interval_late", TriState.DISABLED) + fun filterIntervalLate() = preferenceStore.getEnum( + "pref_filter_library_interval_late", + TriState.DISABLED, + ) - fun filterIntervalDropped() = preferenceStore.getEnum("pref_filter_library_interval_dropped", TriState.DISABLED) + fun filterIntervalDropped() = preferenceStore.getEnum( + "pref_filter_library_interval_dropped", + TriState.DISABLED, + ) - fun filterIntervalPassed() = preferenceStore.getEnum("pref_filter_library_interval_passed", TriState.DISABLED) + fun filterIntervalPassed() = preferenceStore.getEnum( + "pref_filter_library_interval_passed", + TriState.DISABLED, + ) - fun filterTracking(id: Int) = preferenceStore.getEnum("pref_filter_library_tracked_${id}_v2", TriState.DISABLED) + fun filterTracking(id: Int) = preferenceStore.getEnum( + "pref_filter_library_tracked_${id}_v2", + TriState.DISABLED, + ) // endregion @@ -97,24 +140,45 @@ class LibraryPreferences( fun updateCategories() = preferenceStore.getStringSet("library_update_categories", emptySet()) - fun updateCategoriesExclude() = preferenceStore.getStringSet("library_update_categories_exclude", emptySet()) + fun updateCategoriesExclude() = preferenceStore.getStringSet( + "library_update_categories_exclude", + emptySet(), + ) // endregion // region Chapter - fun filterChapterByRead() = preferenceStore.getLong("default_chapter_filter_by_read", Manga.SHOW_ALL) + fun filterChapterByRead() = preferenceStore.getLong( + "default_chapter_filter_by_read", + Manga.SHOW_ALL, + ) - fun filterChapterByDownloaded() = preferenceStore.getLong("default_chapter_filter_by_downloaded", Manga.SHOW_ALL) + fun filterChapterByDownloaded() = preferenceStore.getLong( + "default_chapter_filter_by_downloaded", + Manga.SHOW_ALL, + ) - fun filterChapterByBookmarked() = preferenceStore.getLong("default_chapter_filter_by_bookmarked", Manga.SHOW_ALL) + fun filterChapterByBookmarked() = preferenceStore.getLong( + "default_chapter_filter_by_bookmarked", + Manga.SHOW_ALL, + ) // and upload date - fun sortChapterBySourceOrNumber() = preferenceStore.getLong("default_chapter_sort_by_source_or_number", Manga.CHAPTER_SORTING_SOURCE) + fun sortChapterBySourceOrNumber() = preferenceStore.getLong( + "default_chapter_sort_by_source_or_number", + Manga.CHAPTER_SORTING_SOURCE, + ) - fun displayChapterByNameOrNumber() = preferenceStore.getLong("default_chapter_display_by_name_or_number", Manga.CHAPTER_DISPLAY_NAME) + fun displayChapterByNameOrNumber() = preferenceStore.getLong( + "default_chapter_display_by_name_or_number", + Manga.CHAPTER_DISPLAY_NAME, + ) - fun sortChapterByAscendingOrDescending() = preferenceStore.getLong("default_chapter_sort_by_ascending_or_descending", Manga.CHAPTER_SORT_DESC) + fun sortChapterByAscendingOrDescending() = preferenceStore.getLong( + "default_chapter_sort_by_ascending_or_descending", + Manga.CHAPTER_SORT_DESC, + ) fun setChapterSettingsDefault(manga: Manga) { filterChapterByRead().set(manga.unreadFilterRaw) @@ -122,7 +186,9 @@ class LibraryPreferences( filterChapterByBookmarked().set(manga.bookmarkedFilterRaw) sortChapterBySourceOrNumber().set(manga.sorting) displayChapterByNameOrNumber().set(manga.displayMode) - sortChapterByAscendingOrDescending().set(if (manga.sortDescending()) Manga.CHAPTER_SORT_DESC else Manga.CHAPTER_SORT_ASC) + sortChapterByAscendingOrDescending().set( + if (manga.sortDescending()) Manga.CHAPTER_SORT_DESC else Manga.CHAPTER_SORT_ASC, + ) } fun autoClearChapterCache() = preferenceStore.getBoolean("auto_clear_chapter_cache", false) @@ -131,9 +197,15 @@ class LibraryPreferences( // region Swipe Actions - fun swipeToStartAction() = preferenceStore.getEnum("pref_chapter_swipe_end_action", ChapterSwipeAction.ToggleBookmark) + fun swipeToStartAction() = preferenceStore.getEnum( + "pref_chapter_swipe_end_action", + ChapterSwipeAction.ToggleBookmark, + ) - fun swipeToEndAction() = preferenceStore.getEnum("pref_chapter_swipe_start_action", ChapterSwipeAction.ToggleRead) + fun swipeToEndAction() = preferenceStore.getEnum( + "pref_chapter_swipe_start_action", + ChapterSwipeAction.ToggleRead, + ) // endregion diff --git a/domain/src/main/java/tachiyomi/domain/manga/interactor/SetFetchInterval.kt b/domain/src/main/java/tachiyomi/domain/manga/interactor/SetFetchInterval.kt index 6dc77819e..8be435047 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/interactor/SetFetchInterval.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/interactor/SetFetchInterval.kt @@ -27,7 +27,10 @@ class SetFetchInterval( window } val chapters = getChapterByMangaId.await(manga.id) - val interval = manga.fetchInterval.takeIf { it < 0 } ?: calculateInterval(chapters, dateTime) + val interval = manga.fetchInterval.takeIf { it < 0 } ?: calculateInterval( + chapters, + dateTime, + ) val nextUpdate = calculateNextUpdate(manga, interval, dateTime, currentWindow) return if (manga.nextUpdate == nextUpdate && manga.fetchInterval == interval) { @@ -46,7 +49,9 @@ class SetFetchInterval( internal fun calculateInterval(chapters: List, zonedDateTime: ZonedDateTime): Int { val sortedChapters = chapters - .sortedWith(compareByDescending { it.dateUpload }.thenByDescending { it.dateFetch }) + .sortedWith( + compareByDescending { it.dateUpload }.thenByDescending { it.dateFetch }, + ) .take(50) val uploadDates = sortedChapters @@ -95,7 +100,10 @@ class SetFetchInterval( manga.nextUpdate !in window.first.rangeTo(window.second + 1) || manga.fetchInterval == 0 ) { - val latestDate = ZonedDateTime.ofInstant(Instant.ofEpochMilli(manga.lastUpdate), dateTime.zone) + val latestDate = ZonedDateTime.ofInstant( + Instant.ofEpochMilli(manga.lastUpdate), + dateTime.zone, + ) .toLocalDate() .atStartOfDay() val timeSinceLatest = ChronoUnit.DAYS.between(latestDate, dateTime).toInt() diff --git a/domain/src/main/java/tachiyomi/domain/release/interactor/GetApplicationRelease.kt b/domain/src/main/java/tachiyomi/domain/release/interactor/GetApplicationRelease.kt index 735782fd2..1a0ff4e4b 100644 --- a/domain/src/main/java/tachiyomi/domain/release/interactor/GetApplicationRelease.kt +++ b/domain/src/main/java/tachiyomi/domain/release/interactor/GetApplicationRelease.kt @@ -20,7 +20,10 @@ class GetApplicationRelease( val now = Instant.now() // Limit checks to once every 3 days at most - if (arguments.forceCheck.not() && now.isBefore(Instant.ofEpochMilli(lastChecked.get()).plus(3, ChronoUnit.DAYS))) { + if (arguments.forceCheck.not() && now.isBefore( + Instant.ofEpochMilli(lastChecked.get()).plus(3, ChronoUnit.DAYS), + ) + ) { return Result.NoNewUpdate } @@ -29,7 +32,12 @@ class GetApplicationRelease( lastChecked.set(now.toEpochMilli()) // Check if latest version is different from current version - val isNewVersion = isNewVersion(arguments.isPreview, arguments.commitCount, arguments.versionName, release.version) + val isNewVersion = isNewVersion( + arguments.isPreview, + arguments.commitCount, + arguments.versionName, + release.version, + ) return when { isNewVersion && arguments.isThirdParty -> Result.ThirdPartyInstallation isNewVersion -> Result.NewUpdate(release) @@ -37,7 +45,12 @@ class GetApplicationRelease( } } - private fun isNewVersion(isPreview: Boolean, commitCount: Int, versionName: String, versionTag: String): Boolean { + private fun isNewVersion( + isPreview: Boolean, + commitCount: Int, + versionName: String, + versionTag: String, + ): Boolean { // Removes prefixes like "r" or "v" val newVersion = versionTag.replace("[^\\d.]".toRegex(), "") return if (isPreview) { diff --git a/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt b/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt index 633ba250e..408dee18a 100644 --- a/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt +++ b/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt @@ -34,7 +34,10 @@ class LibraryFlagsTest { @Test fun `Test Flag plus operator with old flag as base`() { - val currentSort = LibrarySort(LibrarySort.Type.UnreadCount, LibrarySort.Direction.Descending) + val currentSort = LibrarySort( + LibrarySort.Type.UnreadCount, + LibrarySort.Direction.Descending, + ) currentSort.flag shouldBe 0b00001100 val sort = LibrarySort(LibrarySort.Type.DateAdded, LibrarySort.Direction.Ascending) diff --git a/domain/src/test/java/tachiyomi/domain/release/interactor/GetApplicationReleaseTest.kt b/domain/src/test/java/tachiyomi/domain/release/interactor/GetApplicationReleaseTest.kt index 41df15221..f813094fe 100644 --- a/domain/src/test/java/tachiyomi/domain/release/interactor/GetApplicationReleaseTest.kt +++ b/domain/src/test/java/tachiyomi/domain/release/interactor/GetApplicationReleaseTest.kt @@ -79,7 +79,9 @@ class GetApplicationReleaseTest { ), ) - (result as GetApplicationRelease.Result.NewUpdate).release shouldBe GetApplicationRelease.Result.NewUpdate(release).release + (result as GetApplicationRelease.Result.NewUpdate).release shouldBe GetApplicationRelease.Result.NewUpdate( + release, + ).release } @Test @@ -106,7 +108,9 @@ class GetApplicationReleaseTest { ), ) - (result as GetApplicationRelease.Result.NewUpdate).release shouldBe GetApplicationRelease.Result.NewUpdate(release).release + (result as GetApplicationRelease.Result.NewUpdate).release shouldBe GetApplicationRelease.Result.NewUpdate( + release, + ).release } @Test diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d9341f8be..8d02a4931 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,7 +90,7 @@ voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version. voyager-tab-navigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" } voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" } -kotlinter = "org.jmailen.gradle:kotlinter-gradle:3.13.0" +ktlint = "org.jlleitschuh.gradle:ktlint-gradle:11.5.1" [bundles] okhttp = ["okhttp-core", "okhttp-logging", "okhttp-dnsoverhttps"] diff --git a/macrobenchmark/src/main/java/tachiyomi/macrobenchmark/StartupBenchmark.kt b/macrobenchmark/src/main/java/tachiyomi/macrobenchmark/StartupBenchmark.kt index cd1002770..87c1d33c1 100644 --- a/macrobenchmark/src/main/java/tachiyomi/macrobenchmark/StartupBenchmark.kt +++ b/macrobenchmark/src/main/java/tachiyomi/macrobenchmark/StartupBenchmark.kt @@ -60,11 +60,16 @@ abstract class AbstractStartupBenchmark(private val startupMode: StartupMode) { @Test fun startupBaselineProfileDisabled() = startup( - CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Disable, warmupIterations = 1), + CompilationMode.Partial( + baselineProfileMode = BaselineProfileMode.Disable, + warmupIterations = 1, + ), ) @Test - fun startupBaselineProfile() = startup(CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require)) + fun startupBaselineProfile() = startup( + CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require), + ) @Test fun startupFullCompilation() = startup(CompilationMode.Full()) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt index 87e17416a..eea05b4ca 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt @@ -182,7 +182,10 @@ fun AdaptiveSheet( shape = MaterialTheme.shapes.extraLarge, tonalElevation = tonalElevation, content = { - BackHandler(enabled = anchoredDraggableState.targetValue == 0, onBack = internalOnDismissRequest) + BackHandler( + enabled = anchoredDraggableState.targetValue == 0, + onBack = internalOnDismissRequest, + ) content() }, ) @@ -200,49 +203,50 @@ fun AdaptiveSheet( } } -private fun AnchoredDraggableState.preUpPostDownNestedScrollConnection() = object : NestedScrollConnection { - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - val delta = available.toFloat() - return if (delta < 0 && source == NestedScrollSource.Drag) { - dispatchRawDelta(delta).toOffset() - } else { - Offset.Zero +private fun AnchoredDraggableState.preUpPostDownNestedScrollConnection() = + object : NestedScrollConnection { + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + val delta = available.toFloat() + return if (delta < 0 && source == NestedScrollSource.Drag) { + dispatchRawDelta(delta).toOffset() + } else { + Offset.Zero + } } - } - override fun onPostScroll( - consumed: Offset, - available: Offset, - source: NestedScrollSource, - ): Offset { - return if (source == NestedScrollSource.Drag) { - dispatchRawDelta(available.toFloat()).toOffset() - } else { - Offset.Zero + override fun onPostScroll( + consumed: Offset, + available: Offset, + source: NestedScrollSource, + ): Offset { + return if (source == NestedScrollSource.Drag) { + dispatchRawDelta(available.toFloat()).toOffset() + } else { + Offset.Zero + } } - } - override suspend fun onPreFling(available: Velocity): Velocity { - val toFling = available.toFloat() - return if (toFling < 0 && offset > anchors.minAnchor()) { - settle(toFling) - // since we go to the anchor with tween settling, consume all for the best UX - available - } else { - Velocity.Zero + override suspend fun onPreFling(available: Velocity): Velocity { + val toFling = available.toFloat() + return if (toFling < 0 && offset > anchors.minAnchor()) { + settle(toFling) + // since we go to the anchor with tween settling, consume all for the best UX + available + } else { + Velocity.Zero + } } + + override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { + settle(velocity = available.toFloat()) + return available + } + + private fun Float.toOffset(): Offset = Offset(0f, this) + + @JvmName("velocityToFloat") + private fun Velocity.toFloat() = this.y + + @JvmName("offsetToFloat") + private fun Offset.toFloat(): Float = this.y } - - override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - settle(velocity = available.toFloat()) - return available - } - - private fun Float.toOffset(): Offset = Offset(0f, this) - - @JvmName("velocityToFloat") - private fun Velocity.toFloat() = this.y - - @JvmName("offsetToFloat") - private fun Offset.toFloat(): Float = this.y -} diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt index dafe3237d..bda305890 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt @@ -37,9 +37,7 @@ import androidx.compose.ui.tooling.preview.Preview * By always rotating we give the feedback to the user that the application isn't 'stuck'. */ @Composable -fun CombinedCircularProgressIndicator( - progress: Float, -) { +fun CombinedCircularProgressIndicator(progress: Float) { val animatedProgress by animateFloatAsState( targetValue = progress, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CollapsibleBox.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CollapsibleBox.kt index b70cb2705..ffd4b84e9 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CollapsibleBox.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CollapsibleBox.kt @@ -23,10 +23,7 @@ import androidx.compose.ui.unit.dp import tachiyomi.presentation.core.theme.header @Composable -fun CollapsibleBox( - heading: String, - content: @Composable () -> Unit, -) { +fun CollapsibleBox(heading: String, content: @Composable () -> Unit) { var expanded by remember { mutableStateOf(false) } Column { diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt index 17dc818ca..86d1225b5 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt @@ -11,12 +11,7 @@ import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.unit.dp @Composable -fun LinkIcon( - modifier: Modifier = Modifier, - label: String, - icon: ImageVector, - url: String, -) { +fun LinkIcon(modifier: Modifier = Modifier, label: String, icon: ImageVector, url: String) { val uriHandler = LocalUriHandler.current IconButton( modifier = modifier.padding(4.dp), diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt index c0ffb35d4..2fe128746 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt @@ -9,10 +9,7 @@ import androidx.compose.ui.text.font.FontWeight import tachiyomi.presentation.core.components.material.padding @Composable -fun ListGroupHeader( - modifier: Modifier = Modifier, - text: String, -) { +fun ListGroupHeader(modifier: Modifier = Modifier, text: String) { Text( text = text, modifier = modifier diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt index f1d544db7..bc7cf7ae3 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt @@ -51,16 +51,12 @@ object SettingsItemsPaddings { } @Composable -fun HeadingItem( - @StringRes labelRes: Int, -) { +fun HeadingItem(@StringRes labelRes: Int) { HeadingItem(stringResource(labelRes)) } @Composable -fun HeadingItem( - text: String, -) { +fun HeadingItem(text: String) { Text( text = text, style = MaterialTheme.typography.header, @@ -74,11 +70,7 @@ fun HeadingItem( } @Composable -fun IconItem( - label: String, - icon: ImageVector, - onClick: () -> Unit, -) { +fun IconItem(label: String, icon: ImageVector, onClick: () -> Unit) { BaseSettingsItem( label = label, widget = { @@ -93,11 +85,7 @@ fun IconItem( } @Composable -fun SortItem( - label: String, - sortDescending: Boolean?, - onClick: () -> Unit, -) { +fun SortItem(label: String, sortDescending: Boolean?, onClick: () -> Unit) { val arrowIcon = when (sortDescending) { true -> Icons.Default.ArrowDownward false -> Icons.Default.ArrowUpward @@ -122,10 +110,7 @@ fun SortItem( } @Composable -fun CheckboxItem( - label: String, - pref: Preference, -) { +fun CheckboxItem(label: String, pref: Preference) { val checked by pref.collectAsState() CheckboxItem( label = label, @@ -135,11 +120,7 @@ fun CheckboxItem( } @Composable -fun CheckboxItem( - label: String, - checked: Boolean, - onClick: () -> Unit, -) { +fun CheckboxItem(label: String, checked: Boolean, onClick: () -> Unit) { BaseSettingsItem( label = label, widget = { @@ -153,11 +134,7 @@ fun CheckboxItem( } @Composable -fun RadioItem( - label: String, - selected: Boolean, - onClick: () -> Unit, -) { +fun RadioItem(label: String, selected: Boolean, onClick: () -> Unit) { BaseSettingsItem( label = label, widget = { @@ -314,11 +291,7 @@ fun TriStateItem( } @Composable -fun TextItem( - label: String, - value: String, - onChange: (String) -> Unit, -) { +fun TextItem(label: String, value: String, onChange: (String) -> Unit) { OutlinedTextField( modifier = Modifier .fillMaxWidth() @@ -331,10 +304,7 @@ fun TextItem( } @Composable -fun SettingsChipRow( - @StringRes labelRes: Int, - content: @Composable FlowRowScope.() -> Unit, -) { +fun SettingsChipRow(@StringRes labelRes: Int, content: @Composable FlowRowScope.() -> Unit) { Column { HeadingItem(labelRes) FlowRow( diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/VerticalFastScroller.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/VerticalFastScroller.kt index c65aa9606..4f44f60e2 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/VerticalFastScroller.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/VerticalFastScroller.kt @@ -197,7 +197,8 @@ private fun rememberColumnWidthSums( horizontalArrangement, contentPadding, ) { - { constraints -> + { + constraints -> require(constraints.maxWidth != Constraints.Infinity) { "LazyVerticalGrid's width should be bound by parent" } diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/AlertDialog.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/AlertDialog.kt index 9bbce88bf..3db94c018 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/AlertDialog.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/AlertDialog.kt @@ -30,7 +30,9 @@ fun AlertDialogContent( title = title, content = { Column { - CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant) { + CompositionLocalProvider( + LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant, + ) { val textStyle = MaterialTheme.typography.bodyMedium ProvideTextStyle(textStyle) { Box( @@ -54,7 +56,9 @@ fun AlertDialogContent( ) .align(Alignment.End), ) { - CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.primary) { + CompositionLocalProvider( + LocalContentColor provides MaterialTheme.colorScheme.primary, + ) { val textStyle = MaterialTheme.typography.labelLarge ProvideTextStyle(value = textStyle, content = buttons) } @@ -86,7 +90,9 @@ fun AlertDialogContent( .fillMaxWidth(), ) { icon?.let { - CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.secondary) { + CompositionLocalProvider( + LocalContentColor provides MaterialTheme.colorScheme.secondary, + ) { Box( Modifier .padding(IconPadding) @@ -97,7 +103,9 @@ fun AlertDialogContent( } } title?.let { - CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) { + CompositionLocalProvider( + LocalContentColor provides MaterialTheme.colorScheme.onSurface, + ) { val textStyle = MaterialTheme.typography.headlineSmall ProvideTextStyle(textStyle) { Box( diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt index 3a5de0275..6a645ed6a 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt @@ -64,20 +64,19 @@ fun TextButton( ), contentPadding: PaddingValues = M3ButtonDefaults.TextButtonContentPadding, content: @Composable RowScope.() -> Unit, -) = - Button( - onClick = onClick, - modifier = modifier, - onLongClick = onLongClick, - enabled = enabled, - interactionSource = interactionSource, - elevation = elevation, - shape = shape, - border = border, - colors = colors, - contentPadding = contentPadding, - content = content, - ) +) = Button( + onClick = onClick, + modifier = modifier, + onLongClick = onLongClick, + enabled = enabled, + interactionSource = interactionSource, + elevation = elevation, + shape = shape, + border = border, + colors = colors, + contentPadding = contentPadding, + content = content, +) /** * Button with additional onLongClick functionality. diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconButton.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconButtonTokens.kt similarity index 100% rename from presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconButton.kt rename to presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconButtonTokens.kt diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/NavigationRail.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/NavigationRail.kt index 02e670ca7..39c00895b 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/NavigationRail.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/NavigationRail.kt @@ -48,7 +48,10 @@ fun NavigationRail( .padding(vertical = MaterialTheme.padding.tiny) .selectableGroup(), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.tiny, alignment = Alignment.CenterVertically), + verticalArrangement = Arrangement.spacedBy( + MaterialTheme.padding.tiny, + alignment = Alignment.CenterVertically, + ), ) { if (header != null) { header() diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt index 7ecd5964c..cd14e2c0e 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt @@ -99,7 +99,9 @@ import kotlin.math.max @Composable fun Scaffold( modifier: Modifier = Modifier, - topBarScrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()), + topBarScrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior( + rememberTopAppBarState(), + ), topBar: @Composable (TopAppBarScrollBehavior) -> Unit = {}, bottomBar: @Composable () -> Unit = {}, startBar: @Composable () -> Unit = {}, @@ -116,7 +118,11 @@ fun Scaffold( androidx.compose.material3.Surface( modifier = Modifier .nestedScroll(topBarScrollBehavior.nestedScrollConnection) - .onConsumedWindowInsetsChanged { remainingWindowInsets.insets = contentWindowInsets.exclude(it) } + .onConsumedWindowInsetsChanged { + remainingWindowInsets.insets = contentWindowInsets.exclude( + it, + ) + } .then(modifier), color = containerColor, contentColor = contentColor, @@ -271,7 +277,10 @@ private fun ScaffoldLayout( } else { max(bottomBarHeightPx.toDp(), fabOffsetDp) }, - start = max(insets.calculateStartPadding((this@SubcomposeLayout).layoutDirection), startBarWidth.toDp()), + start = max( + insets.calculateStartPadding((this@SubcomposeLayout).layoutDirection), + startBarWidth.toDp(), + ), end = insets.calculateEndPadding((this@SubcomposeLayout).layoutDirection), ) content(innerPadding) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Surface.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Surface.kt index eda45695f..71866b61d 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Surface.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Surface.kt @@ -104,9 +104,7 @@ private fun surfaceColorAtElevation(color: Color, elevation: Dp): Color { } } -private fun ColorScheme.surfaceColorAtElevation( - elevation: Dp, -): Color { +private fun ColorScheme.surfaceColorAtElevation(elevation: Dp): Color { if (elevation == 0.dp) return surface val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f return surfaceTint.copy(alpha = alpha).compositeOver(surface) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt index d547ad8d0..66e44ca24 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt @@ -46,10 +46,7 @@ private fun Modifier.tabIndicatorOffset( } @Composable -fun TabIndicator( - currentTabPosition: TabPosition, - currentPageOffsetFraction: Float, -) { +fun TabIndicator(currentTabPosition: TabPosition, currentPageOffsetFraction: Float) { SecondaryIndicator( modifier = Modifier .tabIndicatorOffset(currentTabPosition, currentPageOffsetFraction) @@ -59,10 +56,7 @@ fun TabIndicator( } @Composable -fun TabText( - text: String, - badgeCount: Int? = null, -) { +fun TabText(text: String, badgeCount: Int? = null) { val pillAlpha = if (isSystemInDarkTheme()) 0.12f else 0.08f Row( diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/util/Preview.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/util/ThemePreviews.kt similarity index 100% rename from presentation-core/src/main/java/tachiyomi/presentation/core/util/Preview.kt rename to presentation-core/src/main/java/tachiyomi/presentation/core/util/ThemePreviews.kt diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt index 888acec88..5b537f45d 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt @@ -17,10 +17,7 @@ val CoverWidth = 58.dp val CoverHeight = 87.dp @Composable -fun UpdatesMangaCover( - modifier: GlanceModifier = GlanceModifier, - cover: Bitmap?, -) { +fun UpdatesMangaCover(modifier: GlanceModifier = GlanceModifier, cover: Bitmap?) { Box( modifier = modifier .size(width = CoverWidth, height = CoverHeight) diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt index 15747af98..694dd1e8a 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt @@ -64,7 +64,9 @@ interface Source { "Use the non-RxJava API instead", ReplaceWith("getMangaDetails"), ) - fun fetchMangaDetails(manga: SManga): Observable = throw IllegalStateException("Not used") + fun fetchMangaDetails(manga: SManga): Observable = throw IllegalStateException( + "Not used", + ) /** * Returns an observable with all the available chapters for a manga. @@ -75,7 +77,9 @@ interface Source { "Use the non-RxJava API instead", ReplaceWith("getChapterList"), ) - fun fetchChapterList(manga: SManga): Observable> = throw IllegalStateException("Not used") + fun fetchChapterList(manga: SManga): Observable> = throw IllegalStateException( + "Not used", + ) /** * Returns an observable with the list of pages a chapter has. Pages should be returned diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/Filter.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/Filter.kt index f30b2f52d..99c72e58e 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/Filter.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/Filter.kt @@ -3,7 +3,10 @@ package eu.kanade.tachiyomi.source.model sealed class Filter(val name: String, var state: T) { open class Header(name: String) : Filter(name, 0) open class Separator(name: String = "") : Filter(name, 0) - abstract class Select(name: String, val values: Array, state: Int = 0) : Filter(name, state) + abstract class Select(name: String, val values: Array, state: Int = 0) : Filter( + name, + state, + ) abstract class Text(name: String, state: String = "") : Filter(name, state) abstract class CheckBox(name: String, state: Boolean = false) : Filter(name, state) abstract class TriState(name: String, state: Int = STATE_IGNORE) : Filter(name, state) { diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt index 7378f43a8..5a0acc50e 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt @@ -135,7 +135,11 @@ abstract class HttpSource : CatalogueSource { * @param query the search query. * @param filters the list of filters to apply. */ - override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + override fun fetchSearchManga( + page: Int, + query: String, + filters: FilterList, + ): Observable { return Observable.defer { try { client.newCall(searchMangaRequest(page, query, filters)).asObservableSuccess() @@ -157,7 +161,11 @@ abstract class HttpSource : CatalogueSource { * @param query the search query. * @param filters the list of filters to apply. */ - protected abstract fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request + protected abstract fun searchMangaRequest( + page: Int, + query: String, + filters: FilterList, + ): Request /** * Parses the response from the site and returns a [MangasPage] object. From dbc7fe4d54f12873f8177c6394d97a7750119004 Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 1 Sep 2023 23:09:40 -0400 Subject: [PATCH 04/59] Update linting task in action workflows --- .github/workflows/build_pull_request.yml | 2 +- .github/workflows/build_push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index a9af6d308..2c70e1be7 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -36,4 +36,4 @@ jobs: - name: Build app and run unit tests uses: gradle/gradle-command-action@v2 with: - arguments: lintKotlin assembleStandardRelease testReleaseUnitTest \ No newline at end of file + arguments: ktlintCheck assembleStandardRelease testReleaseUnitTest \ No newline at end of file diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index e49ef19cb..5fb305c69 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -31,7 +31,7 @@ jobs: - name: Build app and run unit tests uses: gradle/gradle-command-action@v2 with: - arguments: lintKotlin assembleStandardRelease testReleaseUnitTest + arguments: ktlintCheck assembleStandardRelease testReleaseUnitTest # Sign APK and create release for tags From 816d7815e94f8b1286e17b1459c3a01a9aba7369 Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Sat, 2 Sep 2023 20:37:25 +0700 Subject: [PATCH 05/59] "Updates" widget for Galaxy Z Flip5 cover screen (#9892) --- app/src/main/AndroidManifest.xml | 14 -- .../src/main/AndroidManifest.xml | 39 ++++- .../widget/BaseUpdatesGridGlanceWidget.kt | 153 ++++++++++++++++++ .../widget/TachiyomiWidgetManager.kt | 3 +- .../UpdatesGridCoverScreenGlanceReceiver.kt | 9 ++ .../UpdatesGridCoverScreenGlanceWidget.kt | 13 ++ .../widget/UpdatesGridGlanceReceiver.kt | 3 +- .../widget/UpdatesGridGlanceWidget.kt | 135 +--------------- .../widget/components/LockedWidget.kt | 11 +- .../widget/components/UpdatesWidget.kt | 93 ++++++----- .../presentation/widget/util/GlanceUtils.kt | 7 +- ...dates_grid_coverscreen_widget_preview.webp | Bin 0 -> 5200 bytes .../updates_grid_widget_preview.webp | Bin .../appwidget_coverscreen_background.xml | 5 + .../layout/appwidget_coverscreen_loading.xml | 14 ++ .../src/main/res/values/colors_appwidget.xml | 1 + .../updates_grid_homescreen_widget_info.xml | 0 .../updates_grid_lockscreen_widget_info.xml | 7 + ...updates_grid_samsung_cover_widget_info.xml | 4 + 19 files changed, 322 insertions(+), 189 deletions(-) create mode 100644 presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt create mode 100644 presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceReceiver.kt create mode 100644 presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceWidget.kt create mode 100644 presentation-widget/src/main/res/drawable-nodpi/updates_grid_coverscreen_widget_preview.webp rename {app => presentation-widget}/src/main/res/drawable-nodpi/updates_grid_widget_preview.webp (100%) create mode 100644 presentation-widget/src/main/res/drawable/appwidget_coverscreen_background.xml create mode 100644 presentation-widget/src/main/res/layout/appwidget_coverscreen_loading.xml rename app/src/main/res/xml/updates_grid_glance_widget_info.xml => presentation-widget/src/main/res/xml/updates_grid_homescreen_widget_info.xml (100%) create mode 100644 presentation-widget/src/main/res/xml/updates_grid_lockscreen_widget_info.xml create mode 100644 presentation-widget/src/main/res/xml/updates_grid_samsung_cover_widget_info.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f8034f711..c3c2f288c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -141,20 +141,6 @@ android:name=".data.notification.NotificationReceiver" android:exported="false" /> - - - - - - - - diff --git a/presentation-widget/src/main/AndroidManifest.xml b/presentation-widget/src/main/AndroidManifest.xml index 568741e54..38943f13e 100644 --- a/presentation-widget/src/main/AndroidManifest.xml +++ b/presentation-widget/src/main/AndroidManifest.xml @@ -1,2 +1,39 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt new file mode 100644 index 000000000..26e1cd918 --- /dev/null +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt @@ -0,0 +1,153 @@ +package tachiyomi.presentation.widget + +import android.app.Application +import android.content.Context +import android.graphics.Bitmap +import android.os.Build +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.unit.Dp +import androidx.core.graphics.drawable.toBitmap +import androidx.glance.GlanceId +import androidx.glance.GlanceModifier +import androidx.glance.ImageProvider +import androidx.glance.appwidget.GlanceAppWidget +import androidx.glance.appwidget.GlanceAppWidgetManager +import androidx.glance.appwidget.SizeMode +import androidx.glance.appwidget.appWidgetBackground +import androidx.glance.appwidget.provideContent +import androidx.glance.background +import androidx.glance.layout.fillMaxSize +import androidx.glance.layout.padding +import androidx.glance.unit.ColorProvider +import coil.executeBlocking +import coil.imageLoader +import coil.request.CachePolicy +import coil.request.ImageRequest +import coil.size.Precision +import coil.size.Scale +import coil.transform.RoundedCornersTransformation +import eu.kanade.tachiyomi.core.security.SecurityPreferences +import eu.kanade.tachiyomi.util.system.dpToPx +import kotlinx.coroutines.flow.map +import tachiyomi.core.util.lang.withIOContext +import tachiyomi.domain.manga.model.MangaCover +import tachiyomi.domain.updates.interactor.GetUpdates +import tachiyomi.domain.updates.model.UpdatesWithRelations +import tachiyomi.presentation.widget.components.CoverHeight +import tachiyomi.presentation.widget.components.CoverWidth +import tachiyomi.presentation.widget.components.LockedWidget +import tachiyomi.presentation.widget.components.UpdatesWidget +import tachiyomi.presentation.widget.util.appWidgetBackgroundRadius +import tachiyomi.presentation.widget.util.calculateRowAndColumnCount +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import java.util.Calendar +import java.util.Date + +abstract class BaseUpdatesGridGlanceWidget( + private val context: Context = Injekt.get(), + private val getUpdates: GetUpdates = Injekt.get(), + private val preferences: SecurityPreferences = Injekt.get(), +) : GlanceAppWidget() { + + override val sizeMode = SizeMode.Exact + + abstract val foreground: ColorProvider + abstract val background: ImageProvider + abstract val topPadding: Dp + abstract val bottomPadding: Dp + + override suspend fun provideGlance(context: Context, id: GlanceId) { + val locked = preferences.useAuthenticator().get() + val containerModifier = GlanceModifier + .fillMaxSize() + .background(background) + .appWidgetBackground() + .padding(top = topPadding, bottom = bottomPadding) + .appWidgetBackgroundRadius() + + val manager = GlanceAppWidgetManager(context) + val ids = manager.getGlanceIds(javaClass) + val (rowCount, columnCount) = ids + .flatMap { manager.getAppWidgetSizes(it) } + .maxBy { it.height.value * it.width.value } + .calculateRowAndColumnCount(topPadding, bottomPadding) + + provideContent { + // If app lock enabled, don't do anything + if (locked) { + LockedWidget( + foreground = foreground, + modifier = containerModifier, + ) + return@provideContent + } + + val flow = remember { + getUpdates + .subscribe(false, DateLimit.timeInMillis) + .map { rawData -> + rawData.prepareData(rowCount, columnCount) + } + } + val data by flow.collectAsState(initial = null) + UpdatesWidget( + data = data, + modifier = containerModifier, + contentColor = foreground, + topPadding = topPadding, + bottomPadding = bottomPadding, + ) + } + } + + private suspend fun List.prepareData( + rowCount: Int, + columnCount: Int, + ): List> { + // Resize to cover size + val widthPx = CoverWidth.value.toInt().dpToPx + val heightPx = CoverHeight.value.toInt().dpToPx + val roundPx = context.resources.getDimension(R.dimen.appwidget_inner_radius) + return withIOContext { + this@prepareData + .distinctBy { it.mangaId } + .take(rowCount * columnCount) + .map { updatesView -> + val request = ImageRequest.Builder(context) + .data( + MangaCover( + mangaId = updatesView.mangaId, + sourceId = updatesView.sourceId, + isMangaFavorite = true, + url = updatesView.coverData.url, + lastModified = updatesView.coverData.lastModified, + ), + ) + .memoryCachePolicy(CachePolicy.DISABLED) + .precision(Precision.EXACT) + .size(widthPx, heightPx) + .scale(Scale.FILL) + .let { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + it.transformations(RoundedCornersTransformation(roundPx)) + } else { + it // Handled by system + } + } + .build() + Pair(updatesView.mangaId, context.imageLoader.executeBlocking(request).drawable?.toBitmap()) + } + } + } + + companion object { + val DateLimit: Calendar + get() = Calendar.getInstance().apply { + time = Date() + add(Calendar.MONTH, -3) + } + } +} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt index e51b0337d..8227c6c51 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt @@ -19,7 +19,7 @@ class TachiyomiWidgetManager( fun Context.init(scope: LifecycleCoroutineScope) { combine( - getUpdates.subscribe(read = false, after = UpdatesGridGlanceWidget.DateLimit.timeInMillis), + getUpdates.subscribe(read = false, after = BaseUpdatesGridGlanceWidget.DateLimit.timeInMillis), securityPreferences.useAuthenticator().changes(), transform = { a, _ -> a }, ) @@ -27,6 +27,7 @@ class TachiyomiWidgetManager( .onEach { try { UpdatesGridGlanceWidget().updateAll(this) + UpdatesGridCoverScreenGlanceWidget().updateAll(this) } catch (e: Exception) { logcat(LogPriority.ERROR, e) { "Failed to update widget" } } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceReceiver.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceReceiver.kt new file mode 100644 index 000000000..721c6a3ac --- /dev/null +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceReceiver.kt @@ -0,0 +1,9 @@ +package tachiyomi.presentation.widget + +import androidx.glance.appwidget.GlanceAppWidget +import androidx.glance.appwidget.GlanceAppWidgetReceiver + +class UpdatesGridCoverScreenGlanceReceiver : GlanceAppWidgetReceiver() { + override val glanceAppWidget: GlanceAppWidget + get() = UpdatesGridCoverScreenGlanceWidget() +} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceWidget.kt new file mode 100644 index 000000000..efb67f1c3 --- /dev/null +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceWidget.kt @@ -0,0 +1,13 @@ +package tachiyomi.presentation.widget + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.glance.ImageProvider +import androidx.glance.unit.ColorProvider + +class UpdatesGridCoverScreenGlanceWidget : BaseUpdatesGridGlanceWidget() { + override val foreground = ColorProvider(Color.White) + override val background = ImageProvider(R.drawable.appwidget_coverscreen_background) + override val topPadding = 0.dp + override val bottomPadding = 24.dp +} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceReceiver.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceReceiver.kt index 93a4cf735..3ee232781 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceReceiver.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceReceiver.kt @@ -4,5 +4,6 @@ import androidx.glance.appwidget.GlanceAppWidget import androidx.glance.appwidget.GlanceAppWidgetReceiver class UpdatesGridGlanceReceiver : GlanceAppWidgetReceiver() { - override val glanceAppWidget: GlanceAppWidget = UpdatesGridGlanceWidget() + override val glanceAppWidget: GlanceAppWidget + get() = UpdatesGridGlanceWidget() } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt index 4275d08f0..2de89ecce 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt @@ -1,133 +1,12 @@ package tachiyomi.presentation.widget -import android.app.Application -import android.content.Context -import android.graphics.Bitmap -import android.os.Build -import androidx.core.graphics.drawable.toBitmap -import androidx.glance.GlanceId -import androidx.glance.GlanceModifier +import androidx.compose.ui.unit.dp import androidx.glance.ImageProvider -import androidx.glance.appwidget.GlanceAppWidget -import androidx.glance.appwidget.GlanceAppWidgetManager -import androidx.glance.appwidget.SizeMode -import androidx.glance.appwidget.appWidgetBackground -import androidx.glance.appwidget.provideContent -import androidx.glance.background -import androidx.glance.layout.fillMaxSize -import coil.executeBlocking -import coil.imageLoader -import coil.request.CachePolicy -import coil.request.ImageRequest -import coil.size.Precision -import coil.size.Scale -import coil.transform.RoundedCornersTransformation -import eu.kanade.tachiyomi.core.security.SecurityPreferences -import eu.kanade.tachiyomi.util.system.dpToPx -import tachiyomi.core.util.lang.withIOContext -import tachiyomi.domain.manga.model.MangaCover -import tachiyomi.domain.updates.interactor.GetUpdates -import tachiyomi.domain.updates.model.UpdatesWithRelations -import tachiyomi.presentation.widget.components.CoverHeight -import tachiyomi.presentation.widget.components.CoverWidth -import tachiyomi.presentation.widget.components.LockedWidget -import tachiyomi.presentation.widget.components.UpdatesWidget -import tachiyomi.presentation.widget.util.appWidgetBackgroundRadius -import tachiyomi.presentation.widget.util.calculateRowAndColumnCount -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import java.util.Calendar -import java.util.Date +import androidx.glance.unit.ColorProvider -class UpdatesGridGlanceWidget( - private val context: Context = Injekt.get(), - private val getUpdates: GetUpdates = Injekt.get(), - private val preferences: SecurityPreferences = Injekt.get(), -) : GlanceAppWidget() { - - private var data: List>? = null - - override val sizeMode = SizeMode.Exact - - override suspend fun provideGlance(context: Context, id: GlanceId) { - val locked = preferences.useAuthenticator().get() - if (!locked) loadData() - - provideContent { - // If app lock enabled, don't do anything - if (locked) { - LockedWidget() - return@provideContent - } - UpdatesWidget(data) - } - } - - private suspend fun loadData() { - val manager = GlanceAppWidgetManager(context) - val ids = manager.getGlanceIds(this@UpdatesGridGlanceWidget::class.java) - if (ids.isEmpty()) return - - withIOContext { - val updates = getUpdates.await( - read = false, - after = DateLimit.timeInMillis, - ) - val (rowCount, columnCount) = ids - .flatMap { manager.getAppWidgetSizes(it) } - .maxBy { it.height.value * it.width.value } - .calculateRowAndColumnCount() - - data = prepareList(updates, rowCount * columnCount) - } - } - - private fun prepareList(processList: List, take: Int): List> { - // Resize to cover size - val widthPx = CoverWidth.value.toInt().dpToPx - val heightPx = CoverHeight.value.toInt().dpToPx - val roundPx = context.resources.getDimension(R.dimen.appwidget_inner_radius) - return processList - .distinctBy { it.mangaId } - .take(take) - .map { updatesView -> - val request = ImageRequest.Builder(context) - .data( - MangaCover( - mangaId = updatesView.mangaId, - sourceId = updatesView.sourceId, - isMangaFavorite = true, - url = updatesView.coverData.url, - lastModified = updatesView.coverData.lastModified, - ), - ) - .memoryCachePolicy(CachePolicy.DISABLED) - .precision(Precision.EXACT) - .size(widthPx, heightPx) - .scale(Scale.FILL) - .let { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { - it.transformations(RoundedCornersTransformation(roundPx)) - } else { - it // Handled by system - } - } - .build() - Pair(updatesView.mangaId, context.imageLoader.executeBlocking(request).drawable?.toBitmap()) - } - } - - companion object { - val DateLimit: Calendar - get() = Calendar.getInstance().apply { - time = Date() - add(Calendar.MONTH, -3) - } - } +class UpdatesGridGlanceWidget : BaseUpdatesGridGlanceWidget() { + override val foreground = ColorProvider(R.color.appwidget_on_secondary_container) + override val background = ImageProvider(R.drawable.appwidget_background) + override val topPadding = 0.dp + override val bottomPadding = 0.dp } - -val ContainerModifier = GlanceModifier - .fillMaxSize() - .background(ImageProvider(R.drawable.appwidget_background)) - .appWidgetBackground() - .appWidgetBackgroundRadius() diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/LockedWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/LockedWidget.kt index 730ab0670..6acb8d7ec 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/LockedWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/LockedWidget.kt @@ -16,26 +16,27 @@ import androidx.glance.text.TextAlign import androidx.glance.text.TextStyle import androidx.glance.unit.ColorProvider import tachiyomi.core.Constants -import tachiyomi.presentation.widget.ContainerModifier import tachiyomi.presentation.widget.R import tachiyomi.presentation.widget.util.stringResource @Composable -fun LockedWidget() { +fun LockedWidget( + foreground: ColorProvider, + modifier: GlanceModifier = GlanceModifier, +) { val intent = Intent(LocalContext.current, Class.forName(Constants.MAIN_ACTIVITY)).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } Box( - modifier = GlanceModifier + modifier = modifier .clickable(actionStartActivity(intent)) - .then(ContainerModifier) .padding(8.dp), contentAlignment = Alignment.Center, ) { Text( text = stringResource(R.string.appwidget_unavailable_locked), style = TextStyle( - color = ColorProvider(R.color.appwidget_on_secondary_container), + color = foreground, fontSize = 12.sp, textAlign = TextAlign.Center, ), diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt index f7ecd2e71..63a3b329d 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt @@ -3,6 +3,7 @@ package tachiyomi.presentation.widget.components import android.content.Intent import android.graphics.Bitmap import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.glance.GlanceModifier import androidx.glance.LocalContext @@ -14,59 +15,75 @@ import androidx.glance.layout.Alignment import androidx.glance.layout.Box import androidx.glance.layout.Column import androidx.glance.layout.Row +import androidx.glance.layout.fillMaxHeight import androidx.glance.layout.fillMaxWidth import androidx.glance.layout.padding import androidx.glance.text.Text +import androidx.glance.text.TextStyle +import androidx.glance.unit.ColorProvider import tachiyomi.core.Constants -import tachiyomi.presentation.widget.ContainerModifier import tachiyomi.presentation.widget.R import tachiyomi.presentation.widget.util.calculateRowAndColumnCount import tachiyomi.presentation.widget.util.stringResource @Composable -fun UpdatesWidget(data: List>?) { - val (rowCount, columnCount) = LocalSize.current.calculateRowAndColumnCount() - Column( - modifier = ContainerModifier, - verticalAlignment = Alignment.CenterVertically, - horizontalAlignment = Alignment.CenterHorizontally, +fun UpdatesWidget( + data: List>?, + modifier: GlanceModifier = GlanceModifier, + contentColor: ColorProvider, + topPadding: Dp, + bottomPadding: Dp, +) { + Box( + contentAlignment = Alignment.Center, + modifier = modifier, ) { if (data == null) { - CircularProgressIndicator() + CircularProgressIndicator(color = contentColor) } else if (data.isEmpty()) { - Text(text = stringResource(R.string.information_no_recent)) + Text( + text = stringResource(R.string.information_no_recent), + style = TextStyle(color = contentColor), + ) } else { - (0.. - val coverRow = (0.. - data.getOrNull(j + (i * columnCount)) - } - if (coverRow.isNotEmpty()) { - Row( - modifier = GlanceModifier - .padding(vertical = 4.dp) - .fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalAlignment = Alignment.CenterVertically, - ) { - coverRow.forEach { (mangaId, cover) -> - Box( - modifier = GlanceModifier - .padding(horizontal = 3.dp), - contentAlignment = Alignment.Center, - ) { - val intent = Intent(LocalContext.current, Class.forName(Constants.MAIN_ACTIVITY)).apply { - action = Constants.SHORTCUT_MANGA - putExtra(Constants.MANGA_EXTRA, mangaId) - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + val (rowCount, columnCount) = LocalSize.current.calculateRowAndColumnCount(topPadding, bottomPadding) + Column( + modifier = GlanceModifier.fillMaxHeight(), + verticalAlignment = Alignment.CenterVertically, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + (0.. + val coverRow = (0.. + data.getOrNull(j + (i * columnCount)) + } + if (coverRow.isNotEmpty()) { + Row( + modifier = GlanceModifier + .padding(vertical = 4.dp) + .fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalAlignment = Alignment.CenterVertically, + ) { + coverRow.forEach { (mangaId, cover) -> + Box( + modifier = GlanceModifier + .padding(horizontal = 3.dp), + contentAlignment = Alignment.Center, + ) { + val intent = Intent(LocalContext.current, Class.forName(Constants.MAIN_ACTIVITY)).apply { + action = Constants.SHORTCUT_MANGA + putExtra(Constants.MANGA_EXTRA, mangaId) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - // https://issuetracker.google.com/issues/238793260 - addCategory(mangaId.toString()) + // https://issuetracker.google.com/issues/238793260 + addCategory(mangaId.toString()) + } + UpdatesMangaCover( + modifier = GlanceModifier.clickable(actionStartActivity(intent)), + cover = cover, + ) } - UpdatesMangaCover( - modifier = GlanceModifier.clickable(actionStartActivity(intent)), - cover = cover, - ) } } } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/util/GlanceUtils.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/util/GlanceUtils.kt index fe8360a0e..51710a1be 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/util/GlanceUtils.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/util/GlanceUtils.kt @@ -2,6 +2,7 @@ package tachiyomi.presentation.widget.util import androidx.annotation.StringRes import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpSize import androidx.glance.GlanceModifier import androidx.glance.LocalContext @@ -34,9 +35,13 @@ fun stringResource(@StringRes id: Int): String { * * @return pair of row and column count */ -fun DpSize.calculateRowAndColumnCount(): Pair { +fun DpSize.calculateRowAndColumnCount( + topPadding: Dp, + bottomPadding: Dp, +): Pair { // Hack: Size provided by Glance manager is not reliable so take at least 1 row and 1 column // Set max to 10 children each direction because of Glance limitation + val height = this.height - topPadding - bottomPadding val rowCount = (height.value / 95).toInt().coerceIn(1, 10) val columnCount = (width.value / 64).toInt().coerceIn(1, 10) return Pair(rowCount, columnCount) diff --git a/presentation-widget/src/main/res/drawable-nodpi/updates_grid_coverscreen_widget_preview.webp b/presentation-widget/src/main/res/drawable-nodpi/updates_grid_coverscreen_widget_preview.webp new file mode 100644 index 0000000000000000000000000000000000000000..b28fb91b9a34e2b9eadbec41cb593ca7d7a93204 GIT binary patch literal 5200 zcmaJ_c|4TgzaQhlW1q2yG6pqv)mSRa3}YE&%TRVnQkD@yS!O0hWN9Kxwn)~Hk}(w~ zQOTCQD1)>h5oHN;NB4JM_j~W_ckk=@<9wcT&hvSl=X^fr{eFLr1K!NcLJR_NHZ`_$ zveUCZ!nQT%ov=q~rYtX6YPMh1Gn2v&pk0-l0gTkqX|`eU8`qfkUiX#ZWuSEM=!KWxLcC!7UyKq$g+0(M14Fz#|L0Gn>@ z3;?ngt>Ju9xf33lZluQ@bS9oov`bvt(2mV z8kg^AS2Z!Z>q5QRFv~DUf1{7;&}olj#bBwY@Ki-t#;=+r8>f?3A|v;e`%@MrKe6{y z`EZdabkU4&C2k)<_MLmai70%lj6I-$ci_1yDpMh;rejmN-m=EZWmT=Wa9!9}e!UYgJAggfk&FJ|}E_vQ|6c{l~u(7(*?V*1ncLjVG(e=Y>LsZImR%usMe) z4i?bOf#cxq4*gId)Elm*Wp3A_{Q2-!E^Y2t4iW6&fVl}IFpCxa-MBGCLs^Oy1ndy^ zo6+UP%BXw89#xA{hK=Q6N-2WIeJ+L|M+SO$IqANQNRm(jhL~uFmWDF4?w~BB72=C~ zIbo3ZB??Iu_qxwrdSm<9l&}f!;*ih&X-+&wMSmv4#@QA>h{Zn`T-7kpq)8LM{oS2XZqEmR=O>6~{$v5PSXoE>;`V&b~?-NP)M&?Vmgf*T-arn?gyve=6##2qki3mB-X%*<$X+6*zhLr zno+)X9CX`ur@O~WHV?NvLbT#0pX1%{(5Ai%xTlmMBBwo$G-isc1_(Bufkobm)JvLr zI4J?Alx{s9>~-9k)$3DmmS%c+$M5aEv_F=KRK#!Tpx21SuB5izw&jH6wO2gXuDTuo-K+)%=byJ{Ehs@~!E2x{X7SxEtjK7LHz`B!$DCK?ct4hTdwm+~ z*6=|Gvp67iOujBf){xii*vu^<=yYPDK%syElZ!}bD!trFAKW|}K+PS0dTy`aibLSb zKu(}=Tj2vQ>dxKAcfDO^eU+DVo!w_7M4^pFuiD~=tRNRNUG+ihP{51H9JB2KEkB>kLk_ogWH0DnJHci3On+x~WV59RpPJF_OxMHU^X;|~JYM>< zpFx@b)c0!k$Jo)9omkxaAF=rNA@cIU_RbbRxQs}x^V8}d#lp<{d}42e2p!}xVVldp zqRuL5#j{!r>+dc-pxRECPRZMUzPD1@7R^q;AER(JIGlXXK3y?oH5U?<_VJkhU`;J| zx@+TZY#BRg86HO{20K|CNG;_sP^uOd7lp&&dmGJ!DSFU7Y40ofDb6@tI(TcY5bdF? zA>u0)Sr&E=9>}UN++Brv)wUYu%Hg zguja7Kcq1l9s$hZaJv)*In1nNT+<(ph)3GAeDxn(OLK`2xnv~xmfBV=x8p#_JFmN*#45G-R*5y&`1^qVB61?g)EX>fCqTEip z6N`kLznU5I<1bFOM2bLUKCDGFgLVCDZzUO;c3|u=HG=$9N)N3P9|ts&U}|d$**wOJ zt#S-87=>yCy^9V~xp&waCE^?XI{^wy_bp#56ipK1K_FW9_!j9~s6&ml(OxOAM;iDO zfDV^(GNujsP!TjmUP{#@EbleyihW|K8$P|@P4z7}# z18oORM?Z8nb?BWEy#N+um1OQONtUDBpLIw}QYZi=#t4ex>IcS4X3`v&P^|izk^sVB+>jqW?w$Jfz_FB@P z#-wYU;e1`%FIE!^rTnyh4Zk>;?S#x@pkL9g+&9}8vV zUmn*r(?CHN{JS3ha2VNz-*}+Zi7j>J!kc8L$VX?xd>P-Egn@=iV!QdsOyJHLG=!sQpHUu&fuICydiA_m`XUEuuG`?A1Lj_*VN98< zC0}JaK-$$b5Rd8=&iiSi zb>&Lys*fKpKl#VY9)B%B$p{eV=ucE7eR=NknyX?~qEF#$+C>;7+NH)>+Gi)>S`C78 zCyt!DYM#bVVsiRHb9{YpRMe^-Momj{Ghgn7rH=^}JuIf`{n6!9u_{HCZiE7y-QjKr z)3u$T*%uo=qHVpI zAVqI>NHU&HgmZ6DjnFWYI@`v*tsM}XY0-Am@Rxy_2Q8(mlCA-?+OuukSXucA6IypF zq)FTD(swXD_~*F4dEXrwP8`Cr?df4L;mlv{kn^`6C}h7)nM7#y6*MZm0(H@vWANys zJKPo6Zqh5b!&k_6^g*T0?mvaI&42~xM(X;{h>CMoBEVR<6h-gn_K(f-OR&x5pSS4$ z64*r?z{2yL48*TK0R3aZ;eHaxMAP2pNcy!}gT;MVA2OA61LdU&ar zN#@uc5jR+H#hWKDzK=;Uhl$}G%njGs;*`e0cGkD*qoU)K(%5@Dej=NVzrGyCi;xyv zXQ%#uwEi!qZOq()57y~^J>fp+4SuY>P+>(n)CFGgN=~%k19Hv_9W3s$=80-H6cK26 zS@$Aq4+vP8kgi6xXQ4!mjSFr&yi4`+(7m<4ALf;2He$YU7Sh!44*qDi0|H+eg@?_t z+pza=L_|f^SZa~EE_Y&)$$mCod!IkIf=Ikeh|xwct@+(T5D@)64Zb|kdV!Qc(}=wg zD2I+&^yGz#xgvgw;Rk71ilHRHN!Qi`E(-ytl%I_F?bz4PN-4AoaL8zbNZtlHS8-jS zTr^aTE|1C2o_;DrsSgqoV7Tvto~cbfG;hx>;u6-fa2o%GfgH?zO|6mKBT$atXTpYr?@xC6-AAANb~i9^bM#R4muz7Q{5Ams z6mB4-9-f#0w|tPMtK9_3Fr z3-eBy{^REfv>3~;F(etQY^eTay2vj^366n-TJ)v0TqLq*zAKqNmsSLg_j)hKP)7ht zaexv6IJOPmBg48>?>*mDxU~cUNM`q0{vhBJUySe+oF1f~(*r2p#&7N0oe;k8(ey?M zj-3{E*O+s%b3q9sy%cUw6+yT`F+?R>Yf-FIQrzSw~8!?7ezs$yOZGS24o}nPKZ+^l&L52b|bzmpOF^ka6N9^)+lh4b! zs4hzh!Q1c{XtHCir0hBG3>6F4sX3)QbRWg_x$+sIO?)Pv*x^3=JgS5700Nvk)a{w! zCo8KUmcoUAWOO8+ti0V($}md9Wt2VA2aN50n%kjsQw{}8 ztRvSxCSgb}5nRy@V-a@Xwv#}q(Ix(wb#kbsa>LjzhQ0)JqD;kxEKg*OUR$fi_qO21 zN@NQybZE-^b@Z##;t=vkgdNd;@e+@H!K%B_iu(~wUTBb! zjSd^qPfO=iIZTGcN0F&kHDJ$QC=M|ty_2qCXZMJ}Hh@8FyW0S?h@&OkSj9UYk(L>* zW`uEA(J;MA4KJOlX@2M9vsr_qS#)CUR75M8q!yv1U+(%)K`KL0@LNrw6rQ%4+hy4J zObo(E;v}zDxz8FmKRjQxo8x>I{o*``^B0t4TlDWBDfnmC=bp}2t8bcv%@LjVpUCYf zxcxVe_InMK*1Wvh-uepm*6Ii)>px3}`ml;OWvy<|yX2?lO<@)M8_uuOb6nao39+W) zA@N&te^I$GOCwyH6*my*8wYf=Cc<3b$?en!|6KyN;Q1Ji_&hvhD!nrFHkbK9!rHXQn?t**@Y^Nk^jWz=k7bYy?0(O zZwc7Q3D0!32FIH%zH5l+`d|$$9NC_U-5=A`c|7S^5T;7wkm#oSB`fz3$0qecW=E`* zd&T`SNI`1Q57#6MhsKqX!K3{*PW%Kg#OU#4mBr?}P)zS*e|C|^|LV*~OP zIleZRYOu?jz})|<>iNg->PW0qYs~He;&eYcj9k#c_JMN_&O@n8WjOqd^iTkmJ8OO8 z)D?~J?lE}AwM5JS%7WVAdK3|xMQ4kTUw1M|zp5r@*@xXmmE)_j_p|Cx17`@<>|!i? zT-pGf0weeO*UEwr$?S84$LM;7RxdfD|<^3l* z<8aV!u4c4TP4t^MB4z$E;#M``!^y;+<|54)n7~*b6tVW4hrw3Te?eN$KeSVhJh9ec zJIWrBavFDhQ$-IS5yo-}Fdj*gT|6$-D!1DnCw%xR=dc#c2ILh*Qs&jw^ydt2m+i8B z9Cc{6n%1^`A(J0M5Z;21KgYuATirk~Xk8&2YHYV+ZpUG)RT{~6rhIK5`@%!Ip_z>; zheb#bJ892&3^BtFT}|UFmEfp%47W<>6O6ayymuT}$AADz0vnxw + + + diff --git a/presentation-widget/src/main/res/layout/appwidget_coverscreen_loading.xml b/presentation-widget/src/main/res/layout/appwidget_coverscreen_loading.xml new file mode 100644 index 000000000..057df58f8 --- /dev/null +++ b/presentation-widget/src/main/res/layout/appwidget_coverscreen_loading.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/presentation-widget/src/main/res/values/colors_appwidget.xml b/presentation-widget/src/main/res/values/colors_appwidget.xml index 7d07ea1f8..a5526c94c 100644 --- a/presentation-widget/src/main/res/values/colors_appwidget.xml +++ b/presentation-widget/src/main/res/values/colors_appwidget.xml @@ -1,6 +1,7 @@ @color/tachiyomi_surface + #00000000 @color/tachiyomi_onSurface @color/tachiyomi_surfaceVariant @color/tachiyomi_onSurfaceVariant diff --git a/app/src/main/res/xml/updates_grid_glance_widget_info.xml b/presentation-widget/src/main/res/xml/updates_grid_homescreen_widget_info.xml similarity index 100% rename from app/src/main/res/xml/updates_grid_glance_widget_info.xml rename to presentation-widget/src/main/res/xml/updates_grid_homescreen_widget_info.xml diff --git a/presentation-widget/src/main/res/xml/updates_grid_lockscreen_widget_info.xml b/presentation-widget/src/main/res/xml/updates_grid_lockscreen_widget_info.xml new file mode 100644 index 000000000..62a91467c --- /dev/null +++ b/presentation-widget/src/main/res/xml/updates_grid_lockscreen_widget_info.xml @@ -0,0 +1,7 @@ + + diff --git a/presentation-widget/src/main/res/xml/updates_grid_samsung_cover_widget_info.xml b/presentation-widget/src/main/res/xml/updates_grid_samsung_cover_widget_info.xml new file mode 100644 index 000000000..5f20ff228 --- /dev/null +++ b/presentation-widget/src/main/res/xml/updates_grid_samsung_cover_widget_info.xml @@ -0,0 +1,4 @@ + + From 3cd3f45c8a47790edb3dd687942dd1539efe27c7 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sat, 2 Sep 2023 15:39:12 +0200 Subject: [PATCH 06/59] Translations update from Hosted Weblate (#9860) Weblate translations Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ar/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cs/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/he/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/it/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ja/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nb_NO/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ne/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/vi/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/ Translation: Tachiyomi/Tachiyomi 0.x Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> Co-authored-by: Ali Aljishi Co-authored-by: Astrid Co-authored-by: DarKCroX Co-authored-by: DatTran MLL Co-authored-by: Dexroneum Co-authored-by: FateXBlood Co-authored-by: Giorgio Sanna Co-authored-by: ID-86 Co-authored-by: Luna Jernberg Co-authored-by: Lyfja Co-authored-by: Lzmxya Co-authored-by: Pitpe11 Co-authored-by: TheKingTermux Co-authored-by: Uzuki Shimamura Co-authored-by: Vetle Ledaal Co-authored-by: bapeey Co-authored-by: gallegonovato Co-authored-by: rzvsrh Co-authored-by: stevenlele --- i18n/src/main/res/values-ar/strings.xml | 5 +- i18n/src/main/res/values-b+es+419/strings.xml | 18 +- i18n/src/main/res/values-be/strings.xml | 1 - i18n/src/main/res/values-bg/strings.xml | 2 - i18n/src/main/res/values-bn/strings.xml | 1 - i18n/src/main/res/values-ca/strings.xml | 2 - i18n/src/main/res/values-ceb/strings.xml | 1 - i18n/src/main/res/values-cs/strings.xml | 5 +- i18n/src/main/res/values-cv/strings.xml | 2 - i18n/src/main/res/values-da/strings.xml | 1 - i18n/src/main/res/values-de/strings.xml | 5 +- i18n/src/main/res/values-el/strings.xml | 5 +- i18n/src/main/res/values-eo/strings.xml | 1 - i18n/src/main/res/values-es/strings.xml | 5 +- i18n/src/main/res/values-eu/strings.xml | 2 - i18n/src/main/res/values-fa/strings.xml | 2 - i18n/src/main/res/values-fi/strings.xml | 2 - i18n/src/main/res/values-fil/strings.xml | 2 - i18n/src/main/res/values-fr/strings.xml | 2 - i18n/src/main/res/values-gl/strings.xml | 2 - i18n/src/main/res/values-he/strings.xml | 278 +++++++++++++++--- i18n/src/main/res/values-hi/strings.xml | 2 - i18n/src/main/res/values-hr/strings.xml | 2 - i18n/src/main/res/values-hu/strings.xml | 2 - i18n/src/main/res/values-in/strings.xml | 2 - i18n/src/main/res/values-it/strings.xml | 5 +- i18n/src/main/res/values-ja/strings.xml | 10 +- i18n/src/main/res/values-jv/strings.xml | 1 - i18n/src/main/res/values-ka-rGE/strings.xml | 1 - i18n/src/main/res/values-kk/strings.xml | 2 - i18n/src/main/res/values-kn/strings.xml | 1 - i18n/src/main/res/values-ko/strings.xml | 2 - i18n/src/main/res/values-lt/strings.xml | 2 - i18n/src/main/res/values-lv/strings.xml | 2 - i18n/src/main/res/values-ms/strings.xml | 18 +- i18n/src/main/res/values-nb-rNO/strings.xml | 7 +- i18n/src/main/res/values-ne/strings.xml | 5 +- i18n/src/main/res/values-nl/strings.xml | 2 - i18n/src/main/res/values-nn/strings.xml | 1 - i18n/src/main/res/values-pl/strings.xml | 2 - i18n/src/main/res/values-pt-rBR/strings.xml | 5 +- i18n/src/main/res/values-pt/strings.xml | 3 +- i18n/src/main/res/values-ro/strings.xml | 2 - i18n/src/main/res/values-ru/strings.xml | 5 +- i18n/src/main/res/values-sa/strings.xml | 1 - i18n/src/main/res/values-sah/strings.xml | 1 - i18n/src/main/res/values-sc/strings.xml | 2 - i18n/src/main/res/values-sk/strings.xml | 2 - i18n/src/main/res/values-sq/strings.xml | 2 - i18n/src/main/res/values-sr/strings.xml | 2 - i18n/src/main/res/values-sv/strings.xml | 5 +- i18n/src/main/res/values-th/strings.xml | 2 - i18n/src/main/res/values-tr/strings.xml | 2 - i18n/src/main/res/values-uk/strings.xml | 2 - i18n/src/main/res/values-uz/strings.xml | 1 - i18n/src/main/res/values-vi/strings.xml | 10 +- i18n/src/main/res/values-zh-rCN/strings.xml | 6 +- i18n/src/main/res/values-zh-rTW/strings.xml | 5 +- 58 files changed, 314 insertions(+), 157 deletions(-) diff --git a/i18n/src/main/res/values-ar/strings.xml b/i18n/src/main/res/values-ar/strings.xml index 6489e8a5e..29e1cf007 100644 --- a/i18n/src/main/res/values-ar/strings.xml +++ b/i18n/src/main/res/values-ar/strings.xml @@ -401,7 +401,6 @@ دليل استخدام المصادر المحلية المثبتة آخر مصدر مُستخدم - التحقق من الموقع الإلكتروني في WebView تم تسجيل الخروج تسجيل الخروج تسجيل الخروج من %1$s؟ @@ -700,7 +699,6 @@ فتح في GitHub احذف بيانات WebView حُذفت بيانات WebView - عند ارتفاع نسبة الشحن‌ لا يوجد مصادر مثبته لا يوجد مصدر المانجا الغير مقروءة @@ -881,4 +879,7 @@ ولوج التتبع أُفسد فهرس التنزيلات اضغط هنا تتحرَّ كلاودفلير + لا اتصال بالإنترنت + خطأ HTTP %d، انظر في WebView + لم نصل %s \ No newline at end of file diff --git a/i18n/src/main/res/values-b+es+419/strings.xml b/i18n/src/main/res/values-b+es+419/strings.xml index 5f1020736..8d6454cdf 100644 --- a/i18n/src/main/res/values-b+es+419/strings.xml +++ b/i18n/src/main/res/values-b+es+419/strings.xml @@ -23,7 +23,7 @@ Agregar categoría Agregar Editar - Actualizar Biblioteca + Actualizar biblioteca Borrar Descargar Marcar anteriores como leído @@ -320,7 +320,6 @@ Última usada Otro Fuente local - Abrir sitio en WebView No se han encontrado resultados No hay más resultados Pestañas @@ -398,8 +397,8 @@ En curso No hay nuevas actualizaciones disponibles Descargar - Seleccione el archivo de copia de seguridad - Seleccione la imagen de portada + Seleccionar archivo de copia de seguridad + Seleccionar imagen de portada Por favor agregue el manga a la biblioteca antes de hacer esto Error al actualizar la portada @@ -663,7 +662,6 @@ Una nueva versión esta disponible desde los lanzamientos oficiales, Toca para aprender a emigrar de lanzamientos F-droid no oficiales. Error al guardar imagen Cerrar - Cuando la batería no está baja Abrir en GitHub Ninguna fuente encontrada No se encontró ninguna fuente instalada @@ -826,4 +824,14 @@ %d días Con resultados + Licenciado - No hay capítulos para mostrar + HTTP %d, comprueba la página web en WebView + Sin conexión a Internet + Índice de descargas invalidado + No se pudo crear un archivo de respaldo + Sincronizando biblioteca + Se completó la sincronización de la biblioteca + Toque aquí para obtener ayuda con Cloudflare + Inicio de sesión para seguimiento + No se pudo acceder a %s \ No newline at end of file diff --git a/i18n/src/main/res/values-be/strings.xml b/i18n/src/main/res/values-be/strings.xml index 8aeeb5dfe..d9d7ec4bb 100644 --- a/i18n/src/main/res/values-be/strings.xml +++ b/i18n/src/main/res/values-be/strings.xml @@ -361,7 +361,6 @@ Ёсць непрачытаныя главы Shizuku не працуе Закрыць - калі батарэя зараджана Устаноўка пашырэнняў… Перамясціць у пачатак спісу Усталёўнік diff --git a/i18n/src/main/res/values-bg/strings.xml b/i18n/src/main/res/values-bg/strings.xml index 9e95b4aff..63af6b664 100644 --- a/i18n/src/main/res/values-bg/strings.xml +++ b/i18n/src/main/res/values-bg/strings.xml @@ -374,7 +374,6 @@ Помощ за локални източници Закачени Последно използвани - Виж уебсайта в WebView Имейл адрес 1 оставаща @@ -668,7 +667,6 @@ Не е инсталиран Пропуснати Обърнат портрет - Когато батерията не е паднала Език Случи се неочаквана грешка Автоматично изтегляне при четене diff --git a/i18n/src/main/res/values-bn/strings.xml b/i18n/src/main/res/values-bn/strings.xml index b44956d03..e1f212a9e 100644 --- a/i18n/src/main/res/values-bn/strings.xml +++ b/i18n/src/main/res/values-bn/strings.xml @@ -460,7 +460,6 @@ স্থানীয় উৎস নির্দেশিকা \"%1$s\" সার্বজনীনভাবে খুঁজুন সর্বশেষ ব্যবহৃত - ওয়েবসাইটটি ওয়েবভিউতে পরীক্ষা করুন ট্যাব গুলি ডাউনলোড করা অধ্যায় লাইব্রেরীর মাঙ্গা diff --git a/i18n/src/main/res/values-ca/strings.xml b/i18n/src/main/res/values-ca/strings.xml index 97f260013..4535a3a38 100644 --- a/i18n/src/main/res/values-ca/strings.xml +++ b/i18n/src/main/res/values-ca/strings.xml @@ -363,7 +363,6 @@ Hi ha actualitzacions de %d extensions Actualitzacions d’extensions - Comproveu el lloc web en una WebView S’està actualitzant la biblioteca Lectura Omet els capítols filtrats @@ -652,7 +651,6 @@ Neteja les dades del WebView S’han netejat les dades del WebView Tanca - Quan la bateria no sigui baixa No s’ha trobat cap font instal·lada No s’ha trobat cap font Nombre de no llegits diff --git a/i18n/src/main/res/values-ceb/strings.xml b/i18n/src/main/res/values-ceb/strings.xml index 43f8e0fb7..e613ada67 100644 --- a/i18n/src/main/res/values-ceb/strings.xml +++ b/i18n/src/main/res/values-ceb/strings.xml @@ -150,7 +150,6 @@ Kada 2 ka adlaw Kada semana Sa dihang nag-charge - Dili ubos ang baterya Mga pagdili: %s Laktawan ang pag-update sa mga titulo Uban sa wala pa mabasa nga (mga) kapitulo diff --git a/i18n/src/main/res/values-cs/strings.xml b/i18n/src/main/res/values-cs/strings.xml index c8b7b05ce..c4579eee4 100644 --- a/i18n/src/main/res/values-cs/strings.xml +++ b/i18n/src/main/res/values-cs/strings.xml @@ -347,7 +347,6 @@ Hledat \"%1$s\" globálně Připnuté Naposledy použitý - Zobrazit stránku ve WebView Karty Stažené kapitoly Z knihovny @@ -685,7 +684,6 @@ Posunutí širokých snímků Počet nepřečtených Poslední kontrola aktualizace - Když baterie není vybitá Nelze otevřít poslední přečtenou kapitolu Vlastní obal Nenainstalováno @@ -833,4 +831,7 @@ Index stažených zneplatněn Nelze vytvořit soubor zálohy Licencováno - Žádné kapitoly k zobrazení + Bez připojení k internetu + Nelze dosáhnout %s + HTTP %d, zkontrolovat web v WebView \ No newline at end of file diff --git a/i18n/src/main/res/values-cv/strings.xml b/i18n/src/main/res/values-cv/strings.xml index bc9e4d457..24f71c2fa 100644 --- a/i18n/src/main/res/values-cv/strings.xml +++ b/i18n/src/main/res/values-cv/strings.xml @@ -389,7 +389,6 @@ Юлашки усӑ курни Ыттисем Вырӑнти ҫӑл куҫ - Эле WebView-ра тӗрӗсле Пӗр тупсӑм та тупӑнман Урӑх тупсӑмсем ҫук Кантӑксем @@ -567,7 +566,6 @@ Wi-Fi урлӑ ҫеҫ «Малалла вула» пускӑч Апа ҫаклатни, ыкран хӳтӗлевӗ - Петтерей тулли чух Чарусем: %s Вуламан сыпӑк(сем) пур Пуҫланӑ diff --git a/i18n/src/main/res/values-da/strings.xml b/i18n/src/main/res/values-da/strings.xml index 1aae251a9..9124fb10a 100644 --- a/i18n/src/main/res/values-da/strings.xml +++ b/i18n/src/main/res/values-da/strings.xml @@ -180,7 +180,6 @@ Hver tredje dag Ugentligt Kun under opladning - Når batteriet ikke et lavt Begrænsninger: %s Spring over opdatering af titler Med ulæst kapitler diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml index d054f8437..6e7b2d728 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -363,7 +363,6 @@ %d Erweiterungsaktualisierungen verfügbar Erweiterungsaktualisierungen - Webseite in WebView prüfen Bibliothek wird aktualisiert Gefilterte Kapitel überspringen Beim Lesen @@ -652,7 +651,6 @@ WebView-Daten löschen WebView-Daten gelöscht Schließen - Wenn der Akkustand nicht niedrig ist Keine installierte Quelle gefunden Keine Quelle gefunden Anzahl an Ungelesenem @@ -817,4 +815,7 @@ Tracking-Login Sicherungsdatei konnte nicht erstellt werden Lizenziert - Keine Kapitel zu zeigen + HTTP %d, überprüfe die Webseite in WebView + Keine Internetverbindung + %s konnte nicht erreicht werden \ No newline at end of file diff --git a/i18n/src/main/res/values-el/strings.xml b/i18n/src/main/res/values-el/strings.xml index 995b310b2..446f90670 100644 --- a/i18n/src/main/res/values-el/strings.xml +++ b/i18n/src/main/res/values-el/strings.xml @@ -334,7 +334,6 @@ Διαθέσιμη ενημέρωση επέκτασης %d διαθέσιμες ενημερώσεις επεκτάσεων - Ελέγξτε τον ιστότοπο στο WebView Έχετε αποσυνδεθεί Αποσύνδεση Αποσύνδεση από %1$s; @@ -652,7 +651,6 @@ Τα δεδομένα WebView διαγράφηκαν Διαγραφή δεδομένων WebView Κλείσιμο - Όταν η μπαταρία δεν είναι χαμηλή Δε βρέθηκε εγκατεστημένη πηγή Αριθμός μη αναγνωσμένων Τελευταίος έλεγχος ενημέρωσης @@ -817,4 +815,7 @@ Σύνδεση παρακολούθησης Δεν ήταν δυνατή η δημιουργία αντιγράφου ασφαλείας Αδειοδοτημένο - Δεν υπάρχουν κεφάλαια προς εμφάνιση + Δεν μπορούσε να φτάσει το %s + HTTP %d, ελέγξτε την ιστοσελίδα στο WebView + Δεν υπάρχει σύνδεση στο διαδίκτυο \ No newline at end of file diff --git a/i18n/src/main/res/values-eo/strings.xml b/i18n/src/main/res/values-eo/strings.xml index 0d91f2c8a..22954687f 100644 --- a/i18n/src/main/res/values-eo/strings.xml +++ b/i18n/src/main/res/values-eo/strings.xml @@ -427,7 +427,6 @@ Nevalida ĉapitra formato Ĉapitro netrovita Loka fonta - Kontroli retejon en WebView Ĝisdatigi kategorion Kontroli por trovi ĝisdatigojn Helpu traduki diff --git a/i18n/src/main/res/values-es/strings.xml b/i18n/src/main/res/values-es/strings.xml index 4c762aeb7..7ecdab79d 100644 --- a/i18n/src/main/res/values-es/strings.xml +++ b/i18n/src/main/res/values-es/strings.xml @@ -400,7 +400,6 @@ %d actualizaciones de extensiones disponibles Actualizando biblioteca - Abrir sitio en WebView Actualizaciones de extensiones Saltar capítulos excluidos por filtros Lectura @@ -695,7 +694,6 @@ Se han limpiado los datos del WebView Limpiar datos del WebView Cerrar - Cuando la batería tenga suficiente carga Todavía no se ha instalado ninguna fuente No se ha encontrado ninguna fuente Última comprobación de actualizaciones @@ -864,4 +862,7 @@ Inicio de sesión de seguimiento No se ha podido crear un archivo de respaldo Con licencia oficial, sin capítulos que mostrar + No se ha podido acceder a %s + HTTP %d, comprueba la página web en WebView + Sin conexión a Internet \ No newline at end of file diff --git a/i18n/src/main/res/values-eu/strings.xml b/i18n/src/main/res/values-eu/strings.xml index 70776f91c..8a944d45f 100644 --- a/i18n/src/main/res/values-eu/strings.xml +++ b/i18n/src/main/res/values-eu/strings.xml @@ -443,7 +443,6 @@ Irakurri gabeko kapituluak ditu Sartu: %s G - Ikusi webgunea WebView-n Besteak Bilaketa globala… Historia ezabatu da @@ -640,7 +639,6 @@ Ezabatu kategoria Itxi App hizkuntza - Bateria baxu ez dagoenean Hizkuntza Bilatu… \"%s\" kategoria ezabatu nahi duzu\? diff --git a/i18n/src/main/res/values-fa/strings.xml b/i18n/src/main/res/values-fa/strings.xml index 3606fbea1..415366568 100644 --- a/i18n/src/main/res/values-fa/strings.xml +++ b/i18n/src/main/res/values-fa/strings.xml @@ -128,7 +128,6 @@ آخرین استفاده دیگر منبع محلی - وب سایت را در WebView بررسی کنید هیچ نتیجه ای یافت نشد نتیجه بیشتری یافت نشد تب ها @@ -559,7 +558,6 @@ با قسمت‌(های) خوانده‌نشده ردیاب‌ها را به طور خودکار تازه کن - هنگامی که باتری کم نیست از به‌روزرسانی ورودی‌ها صرف‌نظر کنید امروز هر 3 روز diff --git a/i18n/src/main/res/values-fi/strings.xml b/i18n/src/main/res/values-fi/strings.xml index bd4a39a51..256bf4abf 100644 --- a/i18n/src/main/res/values-fi/strings.xml +++ b/i18n/src/main/res/values-fi/strings.xml @@ -388,7 +388,6 @@ Vähemmän Enemmän Kiinnitetyt - Katso sivu WebViewissä Luettavana Tarkista päivitykset Viimeksi käytetty @@ -621,7 +620,6 @@ Korkein Kieli Haku… - Kun akku ei ole vähissä Laventeli Sovelluksen kieli Versio diff --git a/i18n/src/main/res/values-fil/strings.xml b/i18n/src/main/res/values-fil/strings.xml index e9698d55e..2625e1750 100644 --- a/i18n/src/main/res/values-fil/strings.xml +++ b/i18n/src/main/res/values-fil/strings.xml @@ -392,7 +392,6 @@ Huling ginamit Iba pa Lokal na Source - Bisitahin ang site sa WebView Walang nakitang resulta Wala na\'ng resulta Mga Tab @@ -652,7 +651,6 @@ Nalinis na ang WebView data Linisin ang WebView data Isara - Kapag di lowbat Walang nakitang naka-install na source Walang nakitang source Huling pag-update diff --git a/i18n/src/main/res/values-fr/strings.xml b/i18n/src/main/res/values-fr/strings.xml index ccc7c76da..f99cf6f4f 100644 --- a/i18n/src/main/res/values-fr/strings.xml +++ b/i18n/src/main/res/values-fr/strings.xml @@ -402,7 +402,6 @@ %d mises à jour d\'extensions disponibles %d mises à jour d\'extensions disponibles - Consultez le site Web de WebView Mise à jour de la bibliothèque Sources En cours @@ -698,7 +697,6 @@ Effacer les données WebView Données WebView effacées Fermer - Quand la batterie n\'est pas faible Aucune source installée trouvée Dernière verification de mise à jour Nombre de non-lus diff --git a/i18n/src/main/res/values-gl/strings.xml b/i18n/src/main/res/values-gl/strings.xml index 5aa5f65b2..78c3b89a4 100644 --- a/i18n/src/main/res/values-gl/strings.xml +++ b/i18n/src/main/res/values-gl/strings.xml @@ -368,7 +368,6 @@ Baixados Idioma da aplicación ErroInterno: Revisa o rexistro de erros para máis información - Cando a batería non estea baixa Información da aplicación Shizuku non se está executando Instala e inicia Shizuku para utilizalo como instalador de extensións. @@ -720,7 +719,6 @@ Páxina anterior Lista de lectura Estás seguro\? - Abrir o sitio web no WebView Outros Estado descoñecido Fonte non instalada: %1$s diff --git a/i18n/src/main/res/values-he/strings.xml b/i18n/src/main/res/values-he/strings.xml index 0c255f305..37f3835c0 100644 --- a/i18n/src/main/res/values-he/strings.xml +++ b/i18n/src/main/res/values-he/strings.xml @@ -3,7 +3,7 @@ עדכונים לתוסף עדכונים לפרק נפוץ - ההורדה מושהית + ההורדות מושהות אין חיבור רשת זמין אין חיבור Wi-Fi זמין לא ניתן להוריד את הפרק בגלל שגיאה בלתי צפויה @@ -21,13 +21,13 @@ גרסה חדשה זמינה! שגיאה בהורדה - לחץ כדי להתקין + לחץ כדי להתקין עדכון מוריד… אין עדכונים חדשים זמינים הורדה בחר קובץ גיבוי בחר תמונת כריכה - אנא הוסף את המנגה לספרייה שלך לפני שתעשה זאת + אנא הוסף את הפריט לספרייה שלך לפני שתעשה זאת עדכון הכריכה נכשל פרקים %1$s ואחד נוסף @@ -74,7 +74,7 @@ הכריכה עודכנה סנן מותאם אישית התמונה נשמרה - אפס את כל הפרקים למאנגה זו + אפס את כל הפרקים לפריט זה פעולה זו תסיר את התאריך הקריאה של פרק זה. האם אתה בטוח\? הקטגוריות נמחקו קטגוריה עם שם זה כבר קיימת! @@ -99,7 +99,7 @@ שגיאה מוריד (%1$d/%2$d) פרקים %1$s - להוסיף מאנגה לספרייה\? + להוסיף לספרייה\? המקור לא הותקן: %1$s למחוק פרקים שירדו\? נוסף לספרייה @@ -111,7 +111,6 @@ חיפוש גלובלי… אחר מאנגה מקומית - בדוק אתר ב-WebView לא נמצאו תוצאות אין תוצאות נוספות מעדכן קטגוריה @@ -167,8 +166,8 @@ לעולם לא תמיד נעילה כאשר אינו פעיל - דורש ביטול נעילה - אבטחה + ביטול נעילה דרוש + אבטחה ופרטיות ניהול התראות תבנית תאריך פעיל @@ -224,8 +223,8 @@ השבתת האופטימיזציה של הסוללה עדכן סטטוס, ציון ופרק אחרון שנקרא משירותי המעקב הרשומות נמחקו - האם אתה בטוח\? פרקים שנקראו וההתקדמות של מנגה שאינה בספרייה יאבדו - מחק את היסטוריית המנגה שאינם שמורים בספריה שלך + האם אתה בטוח\? פרקים שנקראו וההתקדמות של פריטים שאינם בספרייה יאבדו + מחק את היסטוריית הפריטים שאינם שמורים בספריה שלך נקה את מסד הנתונים עוגיות נוקו נקה עוגיות @@ -282,10 +281,10 @@ למתוח התאם לגודל מסך סוג קנה מידה - Webtoon - אנכי - ימין לשמאל - שמאל לימין + רצועה מוארכת + סידור עמודים (אנכי) + סידור עמודים (ימין לשמאל) + סידור עמודים (שמאל לימין) ברירת המחדל של מצב הקריאה שחור לבן @@ -307,7 +306,7 @@ הנפשת מעברי דפים הצג תוכן באזור החתוך תוסף לא מאומת - תוסף זה אינו זמין עוד. + תוסף זה אינו זמין עוד. ייתכן שאינו פועל כצפוי ויכול לגרום לבעיות באפליקציה. מומלץ להסיר את התקנת התוסף. מסך מלא הוסף ערוך @@ -344,12 +343,12 @@ הגדרות היסטוריה פרקים - מנגה + פריטים בספריה קטגוריות שם לחץ אחורה שוב כדי לסגור שחרר את Tachiyomi - שום דבר נקרא לאחרונה + שום דבר לא נקרא לאחרונה אין עידכונים אחרונים סומן רענון עוקבים אוטומטית @@ -358,7 +357,7 @@ התחל להוריד עכשיו נעץ מסך מאובטח - פריטים לשורה + גודל רשת עקוב אחר המערכת בדוק אם יש כריכה ופרטים חדשים בעת עדכון הספרייה סה\"כ פריטים @@ -406,7 +405,7 @@ תאריך הוספה תאריך האחזור של הפרקים דינמי - מנגה הנמצאת בקטגוריית מנועי העדכונים לא תעודכן גם אם היא נכללת בקטגורייה אחרת שכן מתעדכנת. + פריט הנמצא בקטגוריית מנועי העדכונים לא יעודכן גם אם הוא נכלל בקטגורייה אחרת שכן מתעדכנת. הראה פריט עם פרק(ים) שלא נקרא(ו) העבר סדרה לראש @@ -428,7 +427,7 @@ הראה מצב קריאה בלתי רשמי פרטי האפליקצייה - דלג על עדכוני כותרות + דלג על עדכוני פריטים נכשל בקבלת רשימת ההרחבות שו\"ת ומדריכים @@ -462,7 +461,7 @@ הכי נמוך מחק פרקים קטגוריות מוחרגות - מנגה הנמצאת בקטגוריית מנועי ההורדות לא תעודכן גם אם היא נכללת בקטגוריה אחרת שכן נכללת (בהורדות). + פריט הנמצא בקטגוריית מנועי ההורדות לא יעודכן גם אם הוא נכלל בקטגוריה אחרת שכן נכללת (בהורדות). שמור כארכיון CBZ שירותים משופרים גבול @@ -473,25 +472,25 @@ מצב קריאה הורדה אוטומטית אפור - אנכי מתמשך - עמודים + רצועה מוארכת עם רווחים + סידור עמודים מאונך הפוך שמור דפים בתיקיות נפרדות אנכי שניהם פעולות - הראה בלחיצה ארוכה + הצג פעולות בלחיצה ארוכה אוטומטי אפשר מחיקת פרקים שסומנו מנוע - צור תיקיות בהתאם לכותרת המנגה - שירותים המספקים שירותים משופרים למקורות ספציפיים. מנגות יהיו במעקב אוטומטי אחרי הוספה לספרייה שלך. + צור תיקיות בהתאם לכותרת הפריטים + שירותים המספקים שירותים משופרים למקורות ספציפיים. פריטים יהיו במעקב אוטומטי אחרי הוספה לספרייה שלך. מקורות חסרים: קובץ גיבוי לא תקין - הגיבוי לא מכיל שום מנגה. + הגיבוי לא מכיל שום פריטים. מעקב - נקה את זיכרון המטמון של הפרקים כשהאפליקציה נסגרת - יש %1$d מנגה שנמצאות במסד הנתונים אבל לא בספרייה + נקה את זיכרון המטמון של הפרקים כשהאפליקציה עולה + יש %1$d פריטים שנמצאים במסד הנתונים אבל לא בספרייה לשוניות חפש את \"%1$s\" גלובלית מצב לא ידוע @@ -510,7 +509,7 @@ שגיאה בשיתוף הכריכה קבע כברירת המחדל מצב קריאה - מנגה מתוך הספרייה + מהספרייה פרקים שירדו כריכה יותר @@ -544,20 +543,20 @@ 1 נשאר 2 נשארו %1$s נשארו - %1$s נשארו + התחברות נעוץ %02d דקות, %02d שניות השחזור בוטל - עדכונים אוטומטיים מאוד מומלצים. רצוי לשמור עותקים נוספים במקומות אחרים. - מסד הנתונים נקי + רצוי לשמור עותקים נוספים של גיבויים במקומות אחרים בנוסף. + אין מה לנקות בדוק עדכונים סדר ע\"י תאריך מחבר לא ידוע מצב פרטי - סינון כל המנגה בספרייה שלך + סינון כל הפריטים בספרייה שלך אתר מידע שגיאה בשמירת התמונה @@ -569,7 +568,7 @@ הושלם ב %1$s עם שגיאה אחת הושלם ב %1$s עם שתי שגיאות הושלם ב %1$s עם %2$s שגיאות - הושלם ב %1$s עם %2$s שגיאות + רשת בוטל/ה @@ -598,8 +597,7 @@ נכשל איפוס הגדרות מצב הקריאה עדכון אחרון לא נקראו - אין קצת סוללה - הגדרות מיון ותצוגה לכל קטגוריה בנפרד + הגדרות מיון לכל קטגוריה בנפרד מקור לא נמצא %1$d עדכונים דולגו גרסת האנדרואיד הזאת כבר לא נתמכת @@ -607,8 +605,8 @@ רשת רק של הכריכות פתח את יומן האירועים %1$d עדכונים נכשלו - הגדל תמונה אופקית - משפר את ביצועי מצב הקריאה ע\"י חיתוך תמונות גבוהות שירדו. + בצע קירוב לתמונות אופקיות באופן אוטומטי + משפר את ביצועי מצב הקריאה דולג בגלל שהסדרה נגמרה דולג בגלל שיש פרקים שלא נקראו דולג בגלל שאין פרקים שנקראו @@ -618,7 +616,7 @@ דולג פרק אחד, המקור חסר או שהוא סונן החוצה דולגו שני פרקים, המקור חסר או שהם סוננו החוצה דולגו %d פרקים, המקור חסר או שהם סוננו החוצה - דולגו %d פרקים, המקור חסר או שהם סוננו החוצה + מפחית פסים, אך עשוי להשפיע על הביצועים שגיאות @@ -634,7 +632,7 @@ פורמט פרק לא תקין בהפסקה האם תרצה למחוק את הקטגוריה %s\? - פיצול לשני עמודים + פצל עמודים רחבים כמו ספר אלקטרוני גרסה כיסוי @@ -646,10 +644,10 @@ הגבלה מורשת שפת אפליקציה - היפוך שני העמודים + הפוך מיקום של עמודים מפוצלים מדריך מעקב מחק הכל - אם המקום של הפיצול עמוד לא תואם לכיוון הקריאה + אם המקום של העמוד המפוצל לא תואם לכיוון הקריאה כלום איזורי נגיעה הפורמט RARv5 לא נתמך @@ -658,4 +656,198 @@ מדריך למתחיל סטטיסטיקות מקומי + *דרוש + שגיאה פנימית: בדוק ביומני קריסה למידע נוסף + נעילת אפליקציה, מסך מוגן + אתה עומד למחוק את \"%s\" מהספריה שלך + הותחלו + הורדו + גלים + קבע מרווח זמן + קבע מרווח זמן מותאם מראש לטעינה + טען חודשית (28 ימים) + כותרת לא מוכרת + בחר מרווח זמן מותאם אישית + מנהל ההורדות + HTTP %d, בדוק באתר ב-WebView + אין חיבור אינטרנט + קטגוריה ריקה + קטגוריית עדכון + כפתור המשך קריאה + מקורות, הרחבות, חיפוש כללי + מצב קריאה, תצוגה, ניווט + העתק ללוח הכתיבה + הגדרות פרק דיפולטי עודכנו + לא עכשיו + בודק הורדות + מחק הורדות + בדוק 10+ באיחור + נפל\? באיחור 20+ וחודשיים + תקופת בדיקה עברה + העדכון הצפוי הבא + הורד קבצי קריסה, אופטימיזציה לסוללה + לבנדר + %d בכל שורה + + הפרק הבא + שני הפרקים הבאים + %d הפרקים הבאים + + + לחץ כאן לעזרה עם Cloudflare + עמוד %d לא נמצא בעת פיצול + צפה בפריטי הספריה העדכניים ביותר + נכשל במציאת כתובת עמוד %d + כבר קיים פריט בספריה בעל אותו שם. +\n +\nלהמשיך בכל זאת\? + הורדה אוטומטית, הורד את הבאים + נושא, פורמט תאריך וזמן + קטגוריות, עדכון כללי, החלקת פרק + סנכרון חד צדדי, סנכרון משופר + מדריך וגיבויים אוטומטיים + לא נמצאו פריטים בקטגוריה זו + בסדר + + מעקב אחד + שני מעקבים + %d מעקבים + + + ספריה עודכנה לאחרונה ב: %s + פצל תמונות מוארכות (בטא) + שטח תמונה רחבה + הסתר פריטים שכבר בספרייה + הרשאות אחסון לא ניתנו + אין פרטי ספרייה לגיבוי + נכשל ביצירת קובץ גיבוי + מחרוזת משתמש לא תקינה + איפוס מחרוזת משתמש דיפולטית + לא הצליח לפתוח הגדרות מכשיר + לוג מפורט + הדפס דוחות שגיאה מפורטים ליומן המערכת (מוריד ביצועים לאפליקציה) + שכבת על + %d ימים + פתח ב-GitHub + פעולה בהחלקה ימינה + בטל תוקף של אינדקס ההורדות + זמין אבל המקור לא מותקן: %s + סנכרון חד צדדי לעדכון ההתקדמות בפרקים בשיקות המעקב. קבע מעקב עבור פריטים ספציפיים מכפתור המעקב שלהם. + הצג כמות פרקים שלא נקראו בסמל העדכונים + פצל תמונה מוארכת + שומר דוח שגיאות לקובץ עבור שיתוף עם המפתחים + כריכה מותאמת אישית + להסיר תאריך\? + הורד הלאה + פעילות רקע + פריטים במעקב + מחרוזת משתמש דיפולטית + מעבר פרק + בעל רישיון - אין פרקים להראות + הועתק ללוח כתיבה + האם אתה בטוח\? + המקור לא נתמך + לא נמצאה התאמה + לא מותקן + משך קריאה + בעדכון כללי + N/A + לזערה לגבי איך לתקן בעיות בעדכוני ספריה, ראה %1$s + לא יכל להשיג את %s + מחוץ לתקופת הפרסום הצפויה + סובב עמודים רחבים להתאמה + ממש עכשיו + הורד אוטומטית בזמן קריאה + פרטי התחברות למעקב + מיקום לא תקין: %s + מסנכרן ספריה + מחרזות משתמש לא יכולה להיות ריקה + שומש לאחרונה + בבקשה התחבר ל-MAL שוב + פריטים שהושלמו + %s נתקל בשגיאה בלתי צפויה. אנו ממליצים שתשתף את דוחות השגיאה שלך בערוץ התמיכה שלנו בדיסקורד. + נקראו + פריטים + %d שניות + רשימת פריטים בעצירה זמנית + רשימת פריטים שלא הושלמו + פעולת עדכון כבר פועלת + מעקבים + החלף אוריינטציה של עמודים רחבים מסובבים + מעקבים שדורשים התחברות: + רשימת פריטים שהושלמו + ממשק משתמש טאבלט + F-Droid builds לא נתמכים באופן רשמי. +\nלחץ כדי ללמוד עוד. + להסיר את %s ממעקב\? + פעולה זו תסיר את המעקב שלך מקומית. + הסר גם מ-%s + קבע גם עבור כל הפריטים בספריה + רק ברשת בלתי מוגבלת + שתף יומני קריסה + רענן מעקבים + פעולה זו תסיר את תאריך ההתחלה הקודם שלך מ-%s + רשימת קריאה + רשימת תכנונים + רבים + להתחמק / להאיר + רפד בצדדים + סנכרון ספריה הושלם + מרווחי זמן + לא מסוגל לפתוח את הפרק שנקרא לאחרונה + פעולה בהחלקה שמאלה + לחיצה כפולה לקירוב (זום) + עודכן לגרסה %1$s + בסך הכל + שגיאה %1$s: %2$s + עובד רק אם הפרק הנוכחי והפרק הבא כבר הורדו. + דלג על פרקים כפולים + DNS over HTTPS (DoH) + תוקף אינדקס ההורדות בוטל + מידע של WebView נוקה בהצלחה + אפס מצב קריאה ואוריינטציה לכל הסדרות + + הפרק הבא שלא נקרא + שני הפרקים הבאים שלא נקראו + %d הפרקים הבאים שלא נקראו + + + מידע דיבוג + רישיונות מקורות פתוחים + פופולרי + + יום אחד + יומיים + %d ימים + + + + חסר פרק אחד + חסרים שני פרקים + חסרים %1$s פרקים + + + הוסף מעקב + לחלק מהיצרנים יש הגבלות אפליקציה שהורגות תהליכים ברקע. באתר הזה יש עוד מידע לגבי איך לתקן את זה. + פעולה זו תסיר את תאריך הסיום הקודם שלך מ-%s + אופס! + אתחל את האפליקציה + %d שעות + דולג בגלל שהספריה לא דורשת עדכונים + דולג בגלל שלא צפוי פרסום היום + לא נמצאה אפליקציה לאסוף קבצים + במעקב + אין תיאור + בצע אומדן בכל + קבע לעדכון בכל + פרקים %1$s-%2$s + סקירה + יישומון לא זמין כשנעילת האפליקציה מופעלת + הכרח את האפליקציה לבדוק מחדש פרקים שהורדו + נקה מידע של WebView + רענן כריכות ספרייה + בעל תוצאות + ציון ממוצע + בשימוש + %d דקות \ No newline at end of file diff --git a/i18n/src/main/res/values-hi/strings.xml b/i18n/src/main/res/values-hi/strings.xml index c8e28abc6..1d561c2ef 100644 --- a/i18n/src/main/res/values-hi/strings.xml +++ b/i18n/src/main/res/values-hi/strings.xml @@ -363,7 +363,6 @@ %d एक्सटेंशन अपडेट उपलब्ध एक्सटेंशन अपडेट - WebView में वेबसाइट देखें अद्यतन पुस्तकालय पठन फ़िल्टर किए गए अध्यायों को छोड़ें @@ -649,7 +648,6 @@ कोई स्थापित स्रोत नहीं मिला आखिरी आइटम अद्यतन अपठित गिनती - जब बैटरी कम नहीं WebView डेटा साफ हो गया गिटहब में खोलें चित्र सहेजने में त्रुटि diff --git a/i18n/src/main/res/values-hr/strings.xml b/i18n/src/main/res/values-hr/strings.xml index 1dc7fa125..a58cfe039 100644 --- a/i18n/src/main/res/values-hr/strings.xml +++ b/i18n/src/main/res/values-hr/strings.xml @@ -342,7 +342,6 @@ Zadnji korišteni Drugi Lokalni izvor - Provjeri web-stranice pomoću WebView Nema rezultata Nema daljnjih rezultata Ažuriranje kategorije @@ -677,7 +676,6 @@ Zadnja provjera aktualiziranja Rastavi visoke slike (BETA) Samo na mrežom bez ograničenja - Kad se baterija nije slaba Broj nepročitanih Izbriši kategoriju Želiš li izbrisati kategoriju „%s”\? diff --git a/i18n/src/main/res/values-hu/strings.xml b/i18n/src/main/res/values-hu/strings.xml index 071bdd1d5..0040d89e9 100644 --- a/i18n/src/main/res/values-hu/strings.xml +++ b/i18n/src/main/res/values-hu/strings.xml @@ -460,7 +460,6 @@ Beállítás alapértelmezettként Tablet mód Lista elejére - Nézze meg a web oldalt WebView-ban Globális keresés \"%1$s\"-ra/re Nincs több találat Nincs találat @@ -614,7 +613,6 @@ Szűri a könyvtár összes tartalmát Hiba a fedlap megosztása közben Bezár - Ha nem alacsony az akkumulátor tözöttség Fordított álló Megállítva Olvasási lista diff --git a/i18n/src/main/res/values-in/strings.xml b/i18n/src/main/res/values-in/strings.xml index e4c7a8520..e728419c2 100644 --- a/i18n/src/main/res/values-in/strings.xml +++ b/i18n/src/main/res/values-in/strings.xml @@ -366,7 +366,6 @@ Selengkapnya Di pustaka Tambahkan ke pustaka - Cek dalam WebView Lisensi terbuka Gagal memulihkan data dari cadangan Pencadangan data gagal @@ -640,7 +639,6 @@ Membersihkan data WebView Data WebView telah dibersihkan Tutup - Saat baterai tidak lemah Sumber yang diinstal tidak ditemukan Tidak ada sumber yang ditemukan Pembaruan terakhir diff --git a/i18n/src/main/res/values-it/strings.xml b/i18n/src/main/res/values-it/strings.xml index a987815e5..ace83b64e 100644 --- a/i18n/src/main/res/values-it/strings.xml +++ b/i18n/src/main/res/values-it/strings.xml @@ -390,7 +390,6 @@ Per %d voci Cercando nuovi capitoli - Controlla il sito in WebView Indirizzo e-mail Ottimizzazione batteria già disattivata Facilita gli aggiornamenti e i backup in secondo piano @@ -697,7 +696,6 @@ Cancella dati WebView Dati WebView cancellati Chiudi - Quando la batteria non è scarica Nessuna fonte installata trovata Nessuna fonte trovata Conteggio non letti @@ -866,4 +864,7 @@ Login del tracking Non è stato possibile creare un file di backup Licenziato - Nessun capitolo da mostrare + HTTP %d, controlla il sito nella WebView + Nessuna connessione ad internet + %s non raggiungibile \ No newline at end of file diff --git a/i18n/src/main/res/values-ja/strings.xml b/i18n/src/main/res/values-ja/strings.xml index 32156f9e3..c4b2d407b 100644 --- a/i18n/src/main/res/values-ja/strings.xml +++ b/i18n/src/main/res/values-ja/strings.xml @@ -325,7 +325,6 @@ 最新 ソース ローカルソース - WebViewでサイトを開く タブ メールアドレス @@ -640,7 +639,6 @@ 閉じる WebViewデータを消去 WebViewデータを消去しました - バッテリー残量が十分な場合 ソースが見つかりません インストール済みのソースが見つかりません 前回の更新確認 @@ -783,7 +781,7 @@ 今日、連載更新が予想されていないためスキップしました 間隔を設定 - 実績あり + 結果あり %s の追跡を削除しますか\? 毎に評価 ごとに更新するように設定する @@ -798,4 +796,10 @@ ライブラリを同期しました Cloudflareに関するヘルプ情報はこちら ダウンロード インデックスを消去しました + バックアップ ファイルを作成できませんでした + トラッキング サービスにログイン + ライセンス制限あり—章を表示できません + HTTP %d、WebViewでこのWebサイトを確認してください + インターネット接続がありません + %sにアクセスできませんでした \ No newline at end of file diff --git a/i18n/src/main/res/values-jv/strings.xml b/i18n/src/main/res/values-jv/strings.xml index 2b4894dbc..623dfc00c 100644 --- a/i18n/src/main/res/values-jv/strings.xml +++ b/i18n/src/main/res/values-jv/strings.xml @@ -260,7 +260,6 @@ Nganyari metadata otomatis Jaringan gak kebates tok Lewati updatean judul - Pas baterai ora titik Bohoso aplikasi Ekstensi iki ditandatangani nganggo sertifikat sing ora dipercaya lan ora diaktifake. \n diff --git a/i18n/src/main/res/values-ka-rGE/strings.xml b/i18n/src/main/res/values-ka-rGE/strings.xml index 0c733f0c9..6ff46b3d7 100644 --- a/i18n/src/main/res/values-ka-rGE/strings.xml +++ b/i18n/src/main/res/values-ka-rGE/strings.xml @@ -244,7 +244,6 @@ ჩანართები შედეგების სიის დასასრული შედეგი ვერ მოიძებნა - ვებსაიტის ნახვა WebView-ში ლოცალური წყარო სხვა ბოლოს გამოყენებული diff --git a/i18n/src/main/res/values-kk/strings.xml b/i18n/src/main/res/values-kk/strings.xml index 6fbad6634..7cf3f4dca 100644 --- a/i18n/src/main/res/values-kk/strings.xml +++ b/i18n/src/main/res/values-kk/strings.xml @@ -50,7 +50,6 @@ Тізім Жүктелген тараулар Қолданба экранын қорғау - Батарея қуаты аз емес кезінде Қолданба кейпі Динамикалық Жасыл Алма @@ -419,7 +418,6 @@ Электрондық пошта мекенжайы Шығу Белгісіз қателік - Сайтты WebView-де тексеріңіз Дерекқорды тазалау Қателіктер туралы есептерді жіберу Сізде бекітілген дереккөздер жоқ diff --git a/i18n/src/main/res/values-kn/strings.xml b/i18n/src/main/res/values-kn/strings.xml index b6857e6d7..5257f612a 100644 --- a/i18n/src/main/res/values-kn/strings.xml +++ b/i18n/src/main/res/values-kn/strings.xml @@ -363,7 +363,6 @@ ಕೊನೆಯದಾಗಿ ಉಪಯೋಗಿಸಿದ ಇತರೆ ಲೋಕಲ್ ಮೂಲ - ವೆಬ್‌ವೀಕ್ಷಣೆಯಲ್ಲಿ ವೆಬ್‌ಸೈಟ್ ಪರಿಶೀಲಿಸಿ ಯಾವುದೇ ಫಲಿತಾಂಶಗಳು ಕಂಡುಬರಲಿಲ್ಲ ಹೆಚ್ಚಿನ ಫಲಿತಾಂಶಗಳಿಲ್ಲ ವರ್ಗವನ್ನು ನವೀಕರಿಸಲಾಗುತ್ತಿದೆ diff --git a/i18n/src/main/res/values-ko/strings.xml b/i18n/src/main/res/values-ko/strings.xml index 9aa1f7d3f..f4996d9c3 100644 --- a/i18n/src/main/res/values-ko/strings.xml +++ b/i18n/src/main/res/values-ko/strings.xml @@ -482,7 +482,6 @@ 일부 제조사는 백그라운드 서비스를 종료하는 추가적인 제한 사항이 있습니다. 자세한 사항은 웹사이트를 참조하세요. 태블릿 UI - WebView에서 사이트 열기 핀 설정됨 \"%1$s\"를 전체 검색합니다 로컬 저장소 사용법 @@ -642,7 +641,6 @@ 마지막으로 업데이트한 날짜순 읽지 않은 항목 개수순 닫기 - 배터리가 부족하지 않을 때만 WebView 데이터 지우기 WebView 데이터 삭제됨 리더 성능 향상 diff --git a/i18n/src/main/res/values-lt/strings.xml b/i18n/src/main/res/values-lt/strings.xml index 142dfc7f1..97333bc2d 100644 --- a/i18n/src/main/res/values-lt/strings.xml +++ b/i18n/src/main/res/values-lt/strings.xml @@ -458,7 +458,6 @@ Ištrinti viską InternalError: Patikrinkite klaidų žurnalus, kad gautumėte daugiau informacijos Kai duomenys neapmokestinami - Kai baterija nėra išsikrovusi Perkelti seriją į viršų Sekimo priemonės, neprijungtos prie: Pagerina skaitytuvo našumą @@ -609,7 +608,6 @@ Viršelis Prisegtas El. pašto adresas - Patikrinkite svetainę \"WebView\" aplinkoje Pasaulinė paieška… Naujausia Vietos šaltinių vadovas diff --git a/i18n/src/main/res/values-lv/strings.xml b/i18n/src/main/res/values-lv/strings.xml index c71d8f0dd..8ada4db03 100644 --- a/i18n/src/main/res/values-lv/strings.xml +++ b/i18n/src/main/res/values-lv/strings.xml @@ -280,7 +280,6 @@ Yotsuba Pilnīgi melns tumšais režīms Aplikācijas valoda - Ja akumalators nav zems Ar nelasītu(ām) nodaļu(ām) Kas nav sāktas Vienmēr jautāt @@ -482,7 +481,6 @@ Lapaspušu skats Izrakstīties Piesprausts - Pārbaudīt tīmekļa vietni šeit: WebView Citi Tagad jūs esat izrakstījies Cilnes diff --git a/i18n/src/main/res/values-ms/strings.xml b/i18n/src/main/res/values-ms/strings.xml index 708306722..3814b4f28 100644 --- a/i18n/src/main/res/values-ms/strings.xml +++ b/i18n/src/main/res/values-ms/strings.xml @@ -358,7 +358,6 @@ %d kemas kini sambungan tersedia Kemas kini sambungan - Semak laman web dalam WebView Mengemas kini pustaka Membaca Sebaris panjang dengan sela @@ -404,7 +403,7 @@ Selesai dalam %1$s dengan %2$s ralat - Sinkron satu hala untuk kemas kini bab kemajuan dalam sistem penjejakan. Sediakan penjejakan untuk entri individu daripada butang penjejakan mereka. + Menyelaras satu hala untuk kemas kini bab kemajuan dalam sistem penjejakan. Sediakan penjejakan untuk entri individu daripada butang penjejakan mereka. Segar semula muka hadapan pustaka Mengikut tarikh muat naik Data @@ -640,7 +639,6 @@ Hapus data WebView Data WebView dihapuskan Tutup - Apabila bateri tidak lemah Tiada sumber dipasang ditemui Tiada sumber ditemui Bilangan belum dibaca @@ -699,7 +697,7 @@ Kategori, Kemas kini keseluruhan, leret bab Mod membaca, paparan, navigasi Muat turun automatik, muat turun maju - Sinkron kemajuan satu hala, pertingkat sinkron + Menyelaras kemajuan satu hala, pertingkat menyelaras Manual & sandaran automatik Kumpulan log kerosakan, pengoptimuman bateri Kekunci aplikasi, skrin keselamatan @@ -784,7 +782,7 @@ %d hari - Tersuai Jarak Masa + Tersuai jarak masa Diluar jangkaan masa keluaran Anggaran setiap Melepasi tempoh semak @@ -794,4 +792,14 @@ Juga buang daripada %s Padam dimuat turun Mempunyai hasil + Tidak boleh menghasilkan fail sandaran + Berlesen - Tiada bab untuk ditayangkan + Tidak dapat mencapai %s + Menyelaraskan pustaka + Pustaka selesai diselaraskan + Tiada sambungan Internet + Log masuk penjejakan + Indeks muat turun tidak sah + Ketik di sini untuk bantuan berkenaan Cloudflare + HTTP %d, semak laman web dalam WebView \ No newline at end of file diff --git a/i18n/src/main/res/values-nb-rNO/strings.xml b/i18n/src/main/res/values-nb-rNO/strings.xml index ff8522816..f96af916c 100644 --- a/i18n/src/main/res/values-nb-rNO/strings.xml +++ b/i18n/src/main/res/values-nb-rNO/strings.xml @@ -394,7 +394,6 @@ Ukjent status Ukjent forfatter Lokal kildeguide - Sjekk nettsted i WebView %1$s gjenstående %1$s gjenstående @@ -652,7 +651,6 @@ Lukk Slett WebView data WebView data slettet - Batteri er ikke lavt Vel, dette er pinlig Enveis fremdriftssynkronisering, forbedret synkronisering Kilder, utvidelser, globalt søk @@ -779,7 +777,7 @@ Mangler %1$s kapittel Mangler %1$s kapitler - Skift retning på roterte brede sider + Vend orienteringen av roterte brede sider Roter brede sider slik at de passer Debug info %d per rad @@ -814,4 +812,7 @@ Biblioteksynkronisering fullført Trykk her for å få hjelp med Cloudflare Nedlastingsindeksen er ugyldiggjort + Kunne ikke opprette en backup-fil + Lisensiert - Ingen kapitler å vise + Sporingsinnlogging \ No newline at end of file diff --git a/i18n/src/main/res/values-ne/strings.xml b/i18n/src/main/res/values-ne/strings.xml index 9c479844f..6bf9af325 100644 --- a/i18n/src/main/res/values-ne/strings.xml +++ b/i18n/src/main/res/values-ne/strings.xml @@ -473,7 +473,6 @@ कुनै परिणाम फेला परेन पिन गरिएको ग्लोबल रूपमा \"%1$s\" खोज्नुहोस् - WebView मा वेबसाइट जाँच गर्नुहोस् अज्ञात लेखक %1$s बाँकी @@ -661,7 +660,6 @@ पढ्दा स्वत: डाउनलोड गर्नुहोस् म्यानुअल र स्वचालित ब्याकअप एप लक, सुरक्षित स्क्रिन - जब ब्याट्री कम छैन अग्लो छविहरू विभाजित गर्नुहोस् (BETA) थुप्रै अपडेटहरू आइकनमा नपढिएको गणना देखाउनुहोस् @@ -817,4 +815,7 @@ ट्र्याकिङ लगइन ब्याकअप फाइल सिर्जना गर्न असफल भयो लाइसेन्स प्राप्त - देखाउन को लागि कुनै अध्याय छैन + इन्टरनेट जडान छैन + %s मा पुग्न सकिएन + HTTP %d, WebView मा वेबसाइट जाँच गर्नुहोस् \ No newline at end of file diff --git a/i18n/src/main/res/values-nl/strings.xml b/i18n/src/main/res/values-nl/strings.xml index fbde722b2..957d93c98 100644 --- a/i18n/src/main/res/values-nl/strings.xml +++ b/i18n/src/main/res/values-nl/strings.xml @@ -373,7 +373,6 @@ Hulp bij lokale bronnen Vastgepind Laatst gebruikt - Bekijk website in WebView E-mailadres %1$s resterend @@ -668,7 +667,6 @@ Classificatie per leeftijd Grote afbeeldingen splitsen (BETA) Versie - Wanneer de batterij niet leeg is Taal van de applicatie Geen bibliotheek inzendingen om te backuppen Ongelezen aantal diff --git a/i18n/src/main/res/values-nn/strings.xml b/i18n/src/main/res/values-nn/strings.xml index 56824eeff..41326b8e1 100644 --- a/i18n/src/main/res/values-nn/strings.xml +++ b/i18n/src/main/res/values-nn/strings.xml @@ -267,7 +267,6 @@ Manglande kjelder: Sporingstenester ikkje logga inn i: Nokre produsentar har ytterlegare appavgrensingar som drep bakgrunnstenester. Denne nettstaden har meir info om korleis det kan fiksast. - Sjekk nettstad i WebView Nettstaden Sorter etter Dato diff --git a/i18n/src/main/res/values-pl/strings.xml b/i18n/src/main/res/values-pl/strings.xml index c0b03e021..66497759a 100644 --- a/i18n/src/main/res/values-pl/strings.xml +++ b/i18n/src/main/res/values-pl/strings.xml @@ -345,7 +345,6 @@ Dla tej serii Mniej Dodaj do biblioteki - Sprawdź stronę w WebView Adres e-mail Filtruje wszystkie pozycje w twojej bibliotece Tylko pobrane @@ -691,7 +690,6 @@ Nie znaleziono źródła Nie znaleziono zainstalowanego źródła Cóż, to troszkę niezręczne - Kiedy poziom baterii nie jest niski Język Lista czytanych Nowa wersja jest dostępna z oficjalnych wydań. Naciśnij, by dowiedzieć się jak przeprowadzić migrację z nieoficjalnych wydań F-Droid. diff --git a/i18n/src/main/res/values-pt-rBR/strings.xml b/i18n/src/main/res/values-pt-rBR/strings.xml index 51217f683..5e6962fb1 100644 --- a/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/i18n/src/main/res/values-pt-rBR/strings.xml @@ -368,7 +368,6 @@ %d atualizações de extensão disponíveis Atualizações de extensões - Verifique o site na WebView Atualizando a biblioteca Leitura Pular os capítulos filtrados @@ -664,7 +663,6 @@ Limpar os dados da WebView Dados da WebView limpos Fechar - Quando a bateria não está fraca Nenhuma fonte instalada foi encontrada Nenhuma fonte encontrada Contagem de não lidos @@ -833,4 +831,7 @@ Login do monitoramento Não foi possível criar o arquivo do backup Licenciado - Nenhum capítulo para mostrar + HTTP %d, verifique o site na WebView + Sem conexão de internet + Não foi possível resolver %s \ No newline at end of file diff --git a/i18n/src/main/res/values-pt/strings.xml b/i18n/src/main/res/values-pt/strings.xml index 8ef841c58..b216c53ae 100644 --- a/i18n/src/main/res/values-pt/strings.xml +++ b/i18n/src/main/res/values-pt/strings.xml @@ -400,7 +400,6 @@ Atualizando biblioteca Fixado - Verifique o sítio web no WebView Preenchimento lateral Lendo Página longa com espaços @@ -676,7 +675,6 @@ Desativado Grelha apenas de capas Fechar - Quando a bateria não está fraca Mover séries para o topo Ignorado porque a séria está completa Ignorado porque nenhum capítulo foi lido @@ -847,4 +845,5 @@ Próxima atualização esperada Definido para atualizar a cada Pulado, pois nenhum lançamento é esperado para hoje + Deletar dowloand \ No newline at end of file diff --git a/i18n/src/main/res/values-ro/strings.xml b/i18n/src/main/res/values-ro/strings.xml index d004233c4..58d614805 100644 --- a/i18n/src/main/res/values-ro/strings.xml +++ b/i18n/src/main/res/values-ro/strings.xml @@ -368,7 +368,6 @@ %d actualizări de extensii sunt disponibile %d actualizări de extensii sunt disponibile - Verificați site-ul în WebView Se actualizează biblioteca Citind Săriți peste capitolele filtrate @@ -605,7 +604,6 @@ Ar trebui să păstrați copii ale backupurilor și în alte locuri. Îmbunătățește performanța cititorului Închide - Când bateria nu este scăzută Azi Listă de citit Lista de dorințe diff --git a/i18n/src/main/res/values-ru/strings.xml b/i18n/src/main/res/values-ru/strings.xml index 749bcea86..76a5424f0 100644 --- a/i18n/src/main/res/values-ru/strings.xml +++ b/i18n/src/main/res/values-ru/strings.xml @@ -354,7 +354,6 @@ Проверка наличия новых глав Обновление библиотеки - Проверить сайт в WebView Оптимизация батареи уже выключена Помогает с обновлением библиотеки и резервной копией в фоне Отключить оптимизацию батареи @@ -676,7 +675,6 @@ Данные WebView очищены Очистить данные WebView Закрыть - Когда батарея заряжена Не найдено установленных источников Не найдено источников Последняя проверка обновления @@ -849,4 +847,7 @@ Не удалось создать файл резервной копии Лицензировано - Нет глав для показа Вход в сервис отслеживания + HTTP %d, проверить сайт в WebView + Нет подключения к интернету + Не удалось достичь %s \ No newline at end of file diff --git a/i18n/src/main/res/values-sa/strings.xml b/i18n/src/main/res/values-sa/strings.xml index f38bd56e4..73aa8d2f1 100644 --- a/i18n/src/main/res/values-sa/strings.xml +++ b/i18n/src/main/res/values-sa/strings.xml @@ -555,7 +555,6 @@ \"%1$s\" कृते सार्वत्रिकेण अवेक्षताम् %1$s प्रति अन्तर्गच्छतु %1$s इतः बहिर्गच्छानि किम् - जालस्थानं वेबव्यू-तन्त्रांशे मार्गतु मूलं न प्रतिष्ठापितम् - %1$s माङ्गां ग्रन्थालये योजयानि किम् मुखचित्रनवीकरणम् अनुत्तीर्णम् diff --git a/i18n/src/main/res/values-sah/strings.xml b/i18n/src/main/res/values-sah/strings.xml index f1494aa88..3bf1ae52f 100644 --- a/i18n/src/main/res/values-sah/strings.xml +++ b/i18n/src/main/res/values-sah/strings.xml @@ -300,7 +300,6 @@ Бүтэһигинэн туттуллубут Атыттар Локальнай төрүт - Үөп сири WebView\'га көрүн Түмүк суох Эбии түмүк суох Кыбытыктар diff --git a/i18n/src/main/res/values-sc/strings.xml b/i18n/src/main/res/values-sc/strings.xml index 2391ca825..eb9749529 100644 --- a/i18n/src/main/res/values-sc/strings.xml +++ b/i18n/src/main/res/values-sc/strings.xml @@ -363,7 +363,6 @@ B\'ant agiornamentos disponìbiles pro %d estensiones Agiornamentos de sas estensiones - Verìfica su situ web cun WebView Agiornende sa biblioteca Leghende Brinca sos capìtulos filtrados @@ -652,7 +651,6 @@ Isbòida sos datos de WebView Datos de WebView isboidados Serra - Cando sa bateria no est bassa Ùrtimu agiornamentu Contu de non lèghidos Peruna fonte agatada diff --git a/i18n/src/main/res/values-sk/strings.xml b/i18n/src/main/res/values-sk/strings.xml index 95a4fd998..2bbde5925 100644 --- a/i18n/src/main/res/values-sk/strings.xml +++ b/i18n/src/main/res/values-sk/strings.xml @@ -453,7 +453,6 @@ Čo je nové Pomôžte s prekladom Licencia Open Source - Skontrolujte webovú stránku vo WebView Chyba pri zdieľaní obalu %d sledovač @@ -612,7 +611,6 @@ Kapitoly %1$s a %2$d ďalšie Kapitoly %1$s a %2$d ďalších - Keď batéria nie je vybitá Typ rotácie Zatvoriť Záznamy vo vylúčených kategóriách nebudú aktualizované, aj keď sú tiež v zahrnutých kategóriách. diff --git a/i18n/src/main/res/values-sq/strings.xml b/i18n/src/main/res/values-sq/strings.xml index 6476ad2ca..12be2cb40 100644 --- a/i18n/src/main/res/values-sq/strings.xml +++ b/i18n/src/main/res/values-sq/strings.xml @@ -184,7 +184,6 @@ Ekrani i sigurt fsheh përmbajtjen e aplikacionit kur ndërron aplikacionet dhe bllokon screenshots Kjo nuk parandalon shtesat jozyrtare ose potencialisht të shënuara gabimisht që të shfaqin përmbajtjen NSFW (18+) brenda aplikacionit. Portret - Kur bateria nuk është e ulët Kufizimet: %s Përditësimet automatike Çdo 6 orë @@ -595,7 +594,6 @@ Kapitujt e shkarkuar Skedat Nuk ka më rezultate - Kontrolloni faqen e internetit në WebView Burimi lokal Tjetër Fiksuar diff --git a/i18n/src/main/res/values-sr/strings.xml b/i18n/src/main/res/values-sr/strings.xml index ec19957dd..89c666787 100644 --- a/i18n/src/main/res/values-sr/strings.xml +++ b/i18n/src/main/res/values-sr/strings.xml @@ -344,7 +344,6 @@ Водич за локалне изворе Закачено Последње коришћено - Провери вебсајт у WebView Филтрира све наслове у колекцији Провери ажурирања Sajt @@ -662,7 +661,6 @@ Отвори на GitHub-у Грешка при чувању слике Затвори - Батерија није празна Обриши податке WebView-a Подаци WebView-a су обрисани Категорије, глобално ажурирање, листање поглавља diff --git a/i18n/src/main/res/values-sv/strings.xml b/i18n/src/main/res/values-sv/strings.xml index 4e37b056e..aab5ca38a 100644 --- a/i18n/src/main/res/values-sv/strings.xml +++ b/i18n/src/main/res/values-sv/strings.xml @@ -364,7 +364,6 @@ %d tilläggsuppdateringar tillgängliga Uppdaterar biblioteket - Kontrollera webbplatsen i WebView Läser Hoppa över filtrerade kapitel Källor @@ -649,7 +648,6 @@ En ny version finns tillgänglig i de officiella utgåvorna. Tryck på för att lära dig hur du flyttar från inofficiella F-Droid-versioner. Inga biblioteksposter att säkerhetskopiera Öppna på GitHub - När batteriet inte är lågt Rensa data från WebView WebView-data rensas Stäng @@ -817,4 +815,7 @@ Kunde inte skapa en backup-fil Licensierad - Inga kapitel att visa Spårning av inloggning + Ingen internet anslutning + HTTP %d, kolla på webbsida i WebView + Kunde inte nå %s \ No newline at end of file diff --git a/i18n/src/main/res/values-th/strings.xml b/i18n/src/main/res/values-th/strings.xml index 511635a60..e4b39fd7a 100644 --- a/i18n/src/main/res/values-th/strings.xml +++ b/i18n/src/main/res/values-th/strings.xml @@ -451,7 +451,6 @@ ค้นหา \"%1$s\" ในทั้งหมด ที่ตรึงไว้ ใช้ล่าสุด - ตรวจสอบเว็บไซต์ใน WebView แท็บ ตอนที่ดาวน์โหลดแล้ว จากคลัง @@ -640,7 +639,6 @@ ปิด ล้างข้อมูล WebView ล้างข้อมูล WebView แล้ว - ขณะแบตเตอรี่ยังไม่ต่ำ ไม่พบแหล่งที่มาที่ติดตั้งแล้ว ไม่พบแหล่งที่มาใด ๆ จำนวนตอนที่ยังไม่ได้อ่าน diff --git a/i18n/src/main/res/values-tr/strings.xml b/i18n/src/main/res/values-tr/strings.xml index 4739c4b25..b9ee6a9d4 100644 --- a/i18n/src/main/res/values-tr/strings.xml +++ b/i18n/src/main/res/values-tr/strings.xml @@ -362,7 +362,6 @@ Uzantı güncellemesi var %d uzantı güncellemesi var - Web sitesini WebView\'de görüntüle Uzantı güncellemeleri Kitaplık güncelleniyor Okunan @@ -652,7 +651,6 @@ WebView verileri temizlendi WebView verilerini temizle Kapat - Pil düşük olmadığında Kurulu kaynak bulunamadı Kaynak bulunamadı Son güncelleme denetimi diff --git a/i18n/src/main/res/values-uk/strings.xml b/i18n/src/main/res/values-uk/strings.xml index bf43f2527..74c61e397 100644 --- a/i18n/src/main/res/values-uk/strings.xml +++ b/i18n/src/main/res/values-uk/strings.xml @@ -372,7 +372,6 @@ %d наявних оновлень розширень Оновлення розширень - Відкрити сайт у WebView Читання Джерела Оновлення бібліотеки @@ -693,7 +692,6 @@ Тицьніть задля подробиць Не вдається відкрити останній прочитаний розділ Мова застосунку - Коли батарею заряджено Версія Мова Вікові обмеження diff --git a/i18n/src/main/res/values-uz/strings.xml b/i18n/src/main/res/values-uz/strings.xml index 49cf51aef..8dd313fc0 100644 --- a/i18n/src/main/res/values-uz/strings.xml +++ b/i18n/src/main/res/values-uz/strings.xml @@ -271,7 +271,6 @@ Til Portret Har kun - Quvvat past bo\'lmaganda Avtomatik yangilanish O\'chiq Kulrang diff --git a/i18n/src/main/res/values-vi/strings.xml b/i18n/src/main/res/values-vi/strings.xml index 8a904f98d..ecbb35bb4 100644 --- a/i18n/src/main/res/values-vi/strings.xml +++ b/i18n/src/main/res/values-vi/strings.xml @@ -313,7 +313,7 @@ Sao chép Không có danh mục. Nhấn vào dấu cộng để tạo một nhóm từ thư viện. Thường gặp - Nhấn giữ để mở hộp thoại + Nhấn giữ để mở mục hành động Mở bằng WebView Màu 32-bit Bỏ qua chap đã đọc @@ -339,7 +339,6 @@ Kiểm tra các chương cập nhật mới Đang cập nhật thư viện Đã tạm ngưng - Kiểm tra trang web bằng WebView Bạn đã đăng xuất Đăng xuất tài khoản Đăng xuất khỏi %1$s\? @@ -509,7 +508,7 @@ Dữ liệu DNS qua HTTPS (DoH) Mạng - Quá trình phục hồi bị huỷ bỏ + Quá trình khôi phục đã bị ngắt Khôi phục thất bại Đang trong quá trình phục hồi Lưu trữ thất bại @@ -596,7 +595,7 @@ Chủ đề: Âm & Dương Chủ đề: Yotsuba Chế độ đen tuyền - Tùy chỉnh mỗi danh mục cho sắp xếp và hiện thị + Tùy chỉnh mỗi danh mục cho sắp xếp Hướng dẫn theo dõi Dịch vụ nâng cao Dịch vụ cung cấp các tính năng nâng cao cho các nguồn cụ thể. Truyện sẽ tự động theo dõi khi được thêm vào thư viện của bạn. @@ -655,7 +654,7 @@ Chưa bắt đầu đọc %1$d cập nhật được bỏ qua Nhấn để tìm hiểu thêm - Phóng ảnh phong cảnh + Phóng ảnh phong cảnh tự động Hiển thị truyện Xoay ảnh rộng Lưới chỉ mỗi bìa @@ -670,7 +669,6 @@ Một phiên bản mới sẵn sàng từ mục phát hành chính thức. Nhấn để học cách kết hợp các mục phát hành không chính thức từ F-Droid. Lỗi khi lưu ảnh Đóng - Khi pin không quá ít Không có nguồn đã cài tìm thấy Không có nguồn nào được tìm thấy Mở trên GitHub diff --git a/i18n/src/main/res/values-zh-rCN/strings.xml b/i18n/src/main/res/values-zh-rCN/strings.xml index 654ecf2b4..106132330 100644 --- a/i18n/src/main/res/values-zh-rCN/strings.xml +++ b/i18n/src/main/res/values-zh-rCN/strings.xml @@ -358,7 +358,6 @@ %d 个插件可更新 插件更新 - 在 WebView 中检查网站 图源 正在更新书架 阅读 @@ -639,7 +638,6 @@ 打开 GitHub 页面 已清除 WebView 数据 清除 WebView 数据 - 非低电量时 关闭 未找到已安装的图源 未找到图源 @@ -800,4 +798,8 @@ 已清除下载索引 登录进度记录平台 无法创建备份文件 + 已有正版,没有章节可供显示 + 未连接网络 + HTTP %d,请在 WebView 中检查网站 + 无法连接到 %s \ No newline at end of file diff --git a/i18n/src/main/res/values-zh-rTW/strings.xml b/i18n/src/main/res/values-zh-rTW/strings.xml index 3736b238a..264713803 100644 --- a/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/i18n/src/main/res/values-zh-rTW/strings.xml @@ -470,7 +470,6 @@ 清除閱讀記錄 暫停閱讀記錄 無痕模式 - 在 WebView 中檢查網站 找不到檔案選擇器 《%1$s》:%2$s,第 %3$d 頁 來源遷移說明 @@ -640,7 +639,6 @@ 清除 WebView 資料 已清除 WebView 資料 關閉 - 電量充足時 找不到來源 找不到已安裝的來源 上次檢查更新日期 @@ -801,4 +799,7 @@ 登入歷程平台 無法建立備份檔 已有正版,沒有章節可供顯示 + HTTP %d,請在 WebView 中檢查網站 + 沒有網際網路連線 + 無法連上 %s \ No newline at end of file From 66b175a3c8c0bfb339a4101baed3882ba8b22097 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Sep 2023 22:11:25 -0400 Subject: [PATCH 07/59] Update dependency ch.acra:acra-http to v5.11.2 (#9900) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8d02a4931..c14a331c6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -64,7 +64,7 @@ swipe = "me.saket.swipe:swipe:1.2.0" logcat = "com.squareup.logcat:logcat:0.1" -acra-http = "ch.acra:acra-http:5.11.1" +acra-http = "ch.acra:acra-http:5.11.2" firebase-analytics = "com.google.firebase:firebase-analytics-ktx:21.3.0" aboutLibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin", version.ref = "aboutlib_version" } From 5c3d655d9eed42f3a2f6e9e4ea8e232ed7b0df56 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Sep 2023 22:11:31 -0400 Subject: [PATCH 08/59] Update dependency io.kotest:kotest-assertions-core to v5.7.0 (#9901) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c14a331c6..ac7f29ea7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -83,7 +83,7 @@ sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" } junit = "org.junit.jupiter:junit-jupiter:5.10.0" -kotest-assertions = "io.kotest:kotest-assertions-core:5.6.2" +kotest-assertions = "io.kotest:kotest-assertions-core:5.7.0" mockk = "io.mockk:mockk:1.13.7" voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } From 87f3d4bd054d9442fb7af9204bda70a85a43b626 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 3 Sep 2023 10:01:47 -0400 Subject: [PATCH 09/59] Use app name in biometric unlock dialog Mostly for forks to show the right name. --- .../eu/kanade/tachiyomi/ui/security/UnlockActivity.kt | 2 +- i18n/src/main/res/values/strings.xml | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt index b697a98d1..09ec00169 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt @@ -19,7 +19,7 @@ class UnlockActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) startAuthentication( - getString(R.string.unlock_app), + getString(R.string.unlock_app_title, getString(R.string.app_name)), confirmationRequired = false, callback = object : AuthenticatorUtil.AuthenticationCallback() { override fun onAuthenticationError( diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 4da05b909..9512a9f2e 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -37,9 +37,8 @@ Local Downloaded - Unlock Tachiyomi + Unlock %s Authenticate to confirm change - Press back again to exit Settings @@ -299,9 +298,9 @@ Uninstall App info Untrusted extension - This extension was signed with an untrusted certificate and wasn\'t activated.\n\nA malicious extension could read any login credentials stored in Tachiyomi or execute arbitrary code.\n\nBy trusting this certificate you accept these risks. + This extension was signed with an untrusted certificate and wasn\'t activated.\n\nA malicious extension could read any stored login credentials or execute arbitrary code.\n\nBy trusting this certificate you accept these risks. This extension is no longer available. It may not function properly and can cause issues with the app. Uninstalling it is recommended. - This extension is not from the official Tachiyomi extensions list. + This extension is not from the official list. Failed to get extensions list Version Language @@ -902,7 +901,7 @@ Tap here for help with Cloudflare *required - WebView is required for Tachiyomi + WebView is required for the app to function Please update the WebView app for better compatibility Updated default chapter settings From 3f0db60a999cb30ff249ae4cc6a720c2a49c319a Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 3 Sep 2023 10:02:04 -0400 Subject: [PATCH 10/59] Minor updates --- .../more/settings/screen/SettingsBackupScreen.kt | 2 +- .../java/eu/kanade/tachiyomi/data/backup/BackupManager.kt | 5 ++--- .../java/eu/kanade/tachiyomi/data/backup/models/Backup.kt | 4 +++- .../java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt | 8 ++++++-- .../kotlin/eu/kanade/tachiyomi/source/Source.kt | 6 ++++++ 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt index c790f8005..ad2a00380 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt @@ -108,7 +108,7 @@ object SettingsBackupScreen : SearchableSettings { showCreateDialog = false flag = it try { - chooseBackupDir.launch(Backup.getBackupFilename()) + chooseBackupDir.launch(Backup.getFilename()) } catch (e: ActivityNotFoundException) { flag = 0 context.toast(R.string.file_picker_error) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index 35a9ea598..67bb74e97 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt @@ -93,15 +93,14 @@ class BackupManager( // Delete older backups val numberOfBackups = backupPreferences.numberOfBackups().get() - val backupRegex = Regex("""tachiyomi_\d+-\d+-\d+_\d+-\d+.proto.gz""") - dir.listFiles { _, filename -> backupRegex.matches(filename) } + dir.listFiles { _, filename -> Backup.filenameRegex.matches(filename) } .orEmpty() .sortedByDescending { it.name } .drop(numberOfBackups - 1) .forEach { it.delete() } // Create new file to place backup - dir.createFile(Backup.getBackupFilename()) + dir.createFile(Backup.getFilename()) } else { UniFile.fromUri(context, uri) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt index 8a9de244d..089e1f03c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt @@ -16,7 +16,9 @@ data class Backup( ) { companion object { - fun getBackupFilename(): String { + val filenameRegex = """tachiyomi_\d+-\d+-\d+_\d+-\d+.proto.gz""".toRegex() + + fun getFilename(): String { val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date()) return "tachiyomi_$date.proto.gz" } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt index 38583ee64..3f155e7f5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt @@ -8,9 +8,11 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.saveTo import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import logcat.LogPriority import okhttp3.Response import okio.buffer import okio.sink +import tachiyomi.core.util.system.logcat import tachiyomi.domain.chapter.model.Chapter import uy.kohesive.injekt.injectLazy import java.io.File @@ -97,6 +99,7 @@ class ChapterCache(private val context: Context) { editor.commit() editor.abortUnlessCommitted() } catch (e: Exception) { + logcat(LogPriority.WARN, e) { "Failed to put page list to cache" } // Ignore. } finally { editor?.abortUnlessCommitted() @@ -174,7 +177,7 @@ class ChapterCache(private val context: Context) { * @return status of deletion for the file. */ private fun removeFileFromCache(file: String): Boolean { - // Make sure we don't delete the journal file (keeps track of cache). + // Make sure we don't delete the journal file (keeps track of cache) if (file == "journal" || file.startsWith("journal.")) { return false } @@ -182,9 +185,10 @@ class ChapterCache(private val context: Context) { return try { // Remove the extension from the file to get the key of the cache val key = file.substringBeforeLast(".") - // Remove file from cache. + // Remove file from cache diskCache.remove(key) } catch (e: Exception) { + logcat(LogPriority.WARN, e) { "Failed to remove file from cache" } false } } diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt index 694dd1e8a..f140eda74 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt @@ -27,7 +27,9 @@ interface Source { /** * Get the updated details for a manga. * + * @since extensions-lib 1.4 * @param manga the manga to update. + * @return the updated manga. */ @Suppress("DEPRECATION") suspend fun getMangaDetails(manga: SManga): SManga { @@ -37,7 +39,9 @@ interface Source { /** * Get all the available chapters for a manga. * + * @since extensions-lib 1.4 * @param manga the manga to update. + * @return the chapters for the manga. */ @Suppress("DEPRECATION") suspend fun getChapterList(manga: SManga): List { @@ -48,7 +52,9 @@ interface Source { * Get the list of pages a chapter has. Pages should be returned * in the expected order; the index is ignored. * + * @since extensions-lib 1.4 * @param chapter the chapter. + * @return the pages for the chapter. */ @Suppress("DEPRECATION") suspend fun getPageList(chapter: SChapter): List { From d9d143e6be35dc1845dc4e23b40c26df6309b8f9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 3 Sep 2023 10:54:05 -0400 Subject: [PATCH 11/59] Update dependency io.kotest:kotest-assertions-core to v5.7.1 (#9905) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ac7f29ea7..e6a84139c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -83,7 +83,7 @@ sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" } junit = "org.junit.jupiter:junit-jupiter:5.10.0" -kotest-assertions = "io.kotest:kotest-assertions-core:5.7.0" +kotest-assertions = "io.kotest:kotest-assertions-core:5.7.1" mockk = "io.mockk:mockk:1.13.7" voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } From cc018cee182f880ebfe07e45809a98d0f6d73220 Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 7 Sep 2023 22:15:50 -0400 Subject: [PATCH 12/59] Change backup file names We use the application ID now to ensure uniqueness if the same folder is selected between different app versions/forks. This will make more sense once storage settings are unified to a single location. Also changes the file extension while we're at it so people stop accidentally ungzipping it. --- .../java/eu/kanade/tachiyomi/data/backup/models/Backup.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt index 089e1f03c..14d4dd0ae 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.data.backup.models +import eu.kanade.tachiyomi.BuildConfig import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber import java.text.SimpleDateFormat @@ -16,11 +17,11 @@ data class Backup( ) { companion object { - val filenameRegex = """tachiyomi_\d+-\d+-\d+_\d+-\d+.proto.gz""".toRegex() + val filenameRegex = """${BuildConfig.APPLICATION_ID}_\d+-\d+-\d+_\d+-\d+.tachibk""".toRegex() fun getFilename(): String { val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date()) - return "tachiyomi_$date.proto.gz" + return "${BuildConfig.APPLICATION_ID}_$date.tachibk" } } } From 86a3fc77c62421060a6b3278902ebf770b327a9e Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 7 Sep 2023 22:23:10 -0400 Subject: [PATCH 13/59] Bump dependencies --- .github/workflows/build_pull_request.yml | 2 +- .github/workflows/build_push.yml | 2 +- gradle/androidx.versions.toml | 10 +++++----- gradle/libs.versions.toml | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 2c70e1be7..da79440dc 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Clone repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 5fb305c69..6a1f423a3 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Clone repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 7be56fad6..2d9ba703f 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,20 +1,20 @@ [versions] agp_version = "8.1.1" -lifecycle_version = "2.6.1" -paging_version = "3.2.0" +lifecycle_version = "2.6.2" +paging_version = "3.2.1" [libraries] gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" } -annotation = "androidx.annotation:annotation:1.7.0-rc01" +annotation = "androidx.annotation:annotation:1.7.0" appcompat = "androidx.appcompat:appcompat:1.6.1" biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05" constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" -corektx = "androidx.core:core-ktx:1.12.0-rc01" +corektx = "androidx.core:core-ktx:1.12.0" splashscreen = "androidx.core:core-splashscreen:1.0.1" recyclerview = "androidx.recyclerview:recyclerview:1.3.1" viewpager = "androidx.viewpager:viewpager:1.1.0-alpha01" -glance = "androidx.glance:glance-appwidget:1.0.0-rc01" +glance = "androidx.glance:glance-appwidget:1.0.0" profileinstaller = "androidx.profileinstaller:profileinstaller:1.3.1" lifecycle-common = { module = "androidx.lifecycle:lifecycle-common", version.ref = "lifecycle_version" } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e6a84139c..fd2118116 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ shizuku_version = "12.2.0" sqlite = "2.3.1" sqldelight = "2.0.0" leakcanary = "2.12" -voyager = "1.0.0-rc06" +voyager = "1.0.0-rc07" richtext = "0.17.0" [libraries] @@ -83,7 +83,7 @@ sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" } junit = "org.junit.jupiter:junit-jupiter:5.10.0" -kotest-assertions = "io.kotest:kotest-assertions-core:5.7.1" +kotest-assertions = "io.kotest:kotest-assertions-core:5.7.2" mockk = "io.mockk:mockk:1.13.7" voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } From 1668be85875522721ee971afac4b46aa7da343c6 Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 8 Sep 2023 17:38:14 -0400 Subject: [PATCH 14/59] Remove old FastScroller Not sure if this will return to the download queue screen, you really shouldn't be downloading a ton of stuff at once anyway? --- .../ui/download/DownloadQueueScreen.kt | 20 ++-- .../ui/download/DownloadQueueScreenModel.kt | 2 +- .../util/system/DisplayExtensions.kt | 14 --- .../tachiyomi/widget/MaterialFastScroll.kt | 92 ------------------- .../res/drawable/material_thumb_drawable.xml | 17 ---- app/src/main/res/layout/download_list.xml | 25 +---- .../main/res/layout/material_fastscroll.xml | 43 --------- app/src/main/res/values/styles.xml | 15 --- 8 files changed, 11 insertions(+), 217 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/widget/MaterialFastScroll.kt delete mode 100644 app/src/main/res/drawable/material_thumb_drawable.xml delete mode 100644 app/src/main/res/layout/material_fastscroll.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt index 143185634..dcbb4536f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt @@ -1,13 +1,13 @@ package eu.kanade.tachiyomi.ui.download import android.view.LayoutInflater -import android.view.ViewGroup import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.PlayArrow @@ -42,7 +42,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.ViewCompat -import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import androidx.recyclerview.widget.LinearLayoutManager import cafe.adriel.voyager.core.model.rememberScreenModel @@ -243,6 +242,7 @@ object DownloadQueueScreen : Screen() { ) return@Scaffold } + val density = LocalDensity.current val layoutDirection = LocalLayoutDirection.current val left = with(density) { contentPadding.calculateLeftPadding(layoutDirection).toPx().roundToInt() } @@ -252,13 +252,13 @@ object DownloadQueueScreen : Screen() { Box(modifier = Modifier.nestedScroll(nestedScrollConnection)) { AndroidView( + modifier = Modifier.fillMaxWidth(), factory = { context -> screenModel.controllerBinding = DownloadListBinding.inflate(LayoutInflater.from(context)) screenModel.adapter = DownloadAdapter(screenModel.listener) - screenModel.controllerBinding.recycler.adapter = screenModel.adapter + screenModel.controllerBinding.root.adapter = screenModel.adapter screenModel.adapter?.isHandleDragEnabled = true - screenModel.adapter?.fastScroller = screenModel.controllerBinding.fastScroller - screenModel.controllerBinding.recycler.layoutManager = LinearLayoutManager(context) + screenModel.controllerBinding.root.layoutManager = LinearLayoutManager(context) ViewCompat.setNestedScrollingEnabled(screenModel.controllerBinding.root, true) @@ -274,7 +274,7 @@ object DownloadQueueScreen : Screen() { screenModel.controllerBinding.root }, update = { - screenModel.controllerBinding.recycler + screenModel.controllerBinding.root .updatePadding( left = left, top = top, @@ -282,14 +282,6 @@ object DownloadQueueScreen : Screen() { bottom = bottom, ) - screenModel.controllerBinding.fastScroller - .updateLayoutParams { - leftMargin = left - topMargin = top - rightMargin = right - bottomMargin = bottom - } - screenModel.adapter?.updateDataSet(downloadList) }, ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt index 711985887..8eed7a915 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt @@ -258,6 +258,6 @@ class DownloadQueueScreenModel( * @return the holder of the download or null if it's not bound. */ private fun getHolder(download: Download): DownloadHolder? { - return controllerBinding.recycler.findViewHolderForItemId(download.chapter.id) as? DownloadHolder + return controllerBinding.root.findViewHolderForItemId(download.chapter.id) as? DownloadHolder } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt index 50f45ae85..3e2834fd2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt @@ -3,9 +3,7 @@ package eu.kanade.tachiyomi.util.system import android.app.Activity import android.content.Context import android.content.res.Configuration -import android.content.res.Resources import android.os.Build -import android.view.View import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.model.TabletUiMode import uy.kohesive.injekt.Injekt @@ -64,18 +62,6 @@ fun Context.isNightMode(): Boolean { return resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES } -val Resources.isLTR - get() = configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR - -/** - * Converts to px and takes into account LTR/RTL layout. - */ -val Float.dpToPxEnd: Float - get() = ( - this * Resources.getSystem().displayMetrics.density * - if (Resources.getSystem().isLTR) 1 else -1 - ) - /** * Checks whether if the device has a display cutout (i.e. notch, camera cutout, etc.). * diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialFastScroll.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialFastScroll.kt deleted file mode 100644 index 29e9e43e3..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialFastScroll.kt +++ /dev/null @@ -1,92 +0,0 @@ -package eu.kanade.tachiyomi.widget - -import android.annotation.SuppressLint -import android.content.Context -import android.util.AttributeSet -import android.view.MotionEvent -import androidx.core.view.ViewCompat -import dev.chrisbanes.insetter.applyInsetter -import eu.davidea.fastscroller.FastScroller -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.util.system.dpToPxEnd -import eu.kanade.tachiyomi.util.system.isLTR - -class MaterialFastScroll @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - FastScroller(context, attrs) { - - init { - setViewsToUse( - R.layout.material_fastscroll, - R.id.fast_scroller_bubble, - R.id.fast_scroller_handle, - ) - autoHideEnabled = true - ignoreTouchesOutsideHandle = true - - applyInsetter { - type(navigationBars = true) { - margin() - } - } - } - - // Overridden to handle RTL - @SuppressLint("ClickableViewAccessibility") - override fun onTouchEvent(event: MotionEvent): Boolean { - if (recyclerView.computeVerticalScrollRange() <= recyclerView.computeVerticalScrollExtent()) { - return super.onTouchEvent(event) - } - - when (event.action) { - MotionEvent.ACTION_DOWN -> { - // start: handle RTL differently - if ( - if (context.resources.isLTR) { - event.x < handle.x - ViewCompat.getPaddingStart(handle) - } else { - event.x > handle.width + ViewCompat.getPaddingStart(handle) - } - ) { - return false - } - // end - - if (ignoreTouchesOutsideHandle && - (event.y < handle.y || event.y > handle.y + handle.height) - ) { - return false - } - handle.isSelected = true - notifyScrollStateChange(true) - showBubble() - showScrollbar() - val y = event.y - setBubbleAndHandlePosition(y) - setRecyclerViewPosition(y) - return true - } - MotionEvent.ACTION_MOVE -> { - val y = event.y - setBubbleAndHandlePosition(y) - setRecyclerViewPosition(y) - return true - } - MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { - handle.isSelected = false - notifyScrollStateChange(false) - hideBubble() - if (autoHideEnabled) hideScrollbar() - return true - } - } - return super.onTouchEvent(event) - } - - override fun setBubbleAndHandlePosition(y: Float) { - super.setBubbleAndHandlePosition(y) - if (bubbleEnabled) { - bubble.y = handle.y - bubble.height / 2f + handle.height / 2f - bubble.translationX = (-45f).dpToPxEnd - } - } -} diff --git a/app/src/main/res/drawable/material_thumb_drawable.xml b/app/src/main/res/drawable/material_thumb_drawable.xml deleted file mode 100644 index 2e550c0df..000000000 --- a/app/src/main/res/drawable/material_thumb_drawable.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/download_list.xml b/app/src/main/res/layout/download_list.xml index e2c96ff12..ec3e3bab9 100644 --- a/app/src/main/res/layout/download_list.xml +++ b/app/src/main/res/layout/download_list.xml @@ -1,24 +1,7 @@ - - - - - - - + android:layout_height="match_parent" + android:clipToPadding="false" + tools:listitem="@layout/download_item" /> diff --git a/app/src/main/res/layout/material_fastscroll.xml b/app/src/main/res/layout/material_fastscroll.xml deleted file mode 100644 index 56b16a1b8..000000000 --- a/app/src/main/res/layout/material_fastscroll.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 14dc1a13a..22313ff42 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -56,21 +56,6 @@ - - - - - From 26c5d761da4ba577481f41e63f03952b8a6c323f Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 8 Sep 2023 17:28:04 -0400 Subject: [PATCH 15/59] Add more replacement suspend functions for source APIs These are basically 1-to-1 replacements for the existing RxJava APIs. This will make the initial migration off of RxJava simpler. We'll revisit the actual call flows in followup versions of the API. --- .../tachiyomi/data/download/Downloader.kt | 3 +- .../source/globalsearch/SearchScreenModel.kt | 3 +- .../ui/reader/loader/HttpPageLoader.kt | 3 +- .../tachiyomi/network/OkHttpExtensions.kt | 21 +++--- .../data/source/SourcePagingSource.kt | 7 +- .../domain/source/model/StubSource.kt | 31 ++------- .../tachiyomi/source/CatalogueSource.kt | 46 +++++++++++-- .../tachiyomi/source/ConfigurableSource.kt | 13 ++++ .../eu/kanade/tachiyomi/source/Source.kt | 35 +++------- .../tachiyomi/source/online/HttpSource.kt | 69 +++++++++++++------ .../source/online/HttpSourceFetcher.kt | 25 ------- .../tachiyomi/source/local/LocalSource.kt | 9 ++- 12 files changed, 137 insertions(+), 128 deletions(-) delete mode 100644 source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index 4ae5cfade..9a15967f4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -43,7 +43,6 @@ import nl.adaptivity.xmlutil.serialization.XML import okhttp3.Response import tachiyomi.core.metadata.comicinfo.COMIC_INFO_FILE import tachiyomi.core.metadata.comicinfo.ComicInfo -import tachiyomi.core.util.lang.awaitSingle import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.launchNow import tachiyomi.core.util.lang.withIOContext @@ -363,7 +362,7 @@ class Downloader( if (page.imageUrl.isNullOrEmpty()) { page.status = Page.State.LOAD_PAGE try { - page.imageUrl = download.source.fetchImageUrl(page).awaitSingle() + page.imageUrl = download.source.getImageUrl(page) } catch (e: Throwable) { page.status = Page.State.ERROR } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt index 55c2e151b..276af54ee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt @@ -19,7 +19,6 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import tachiyomi.core.util.lang.awaitSingle import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.model.Manga @@ -140,7 +139,7 @@ abstract class SearchScreenModel( try { val page = withContext(coroutineDispatcher) { - source.fetchSearchManga(1, query, source.getFilterList()).awaitSingle() + source.getSearchManga(1, query, source.getFilterList()) } val titles = page.mangas.map { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt index 38ec9361d..4802708a6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt @@ -15,7 +15,6 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flow import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.suspendCancellableCoroutine -import tachiyomi.core.util.lang.awaitSingle import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.withIOContext import uy.kohesive.injekt.Injekt @@ -170,7 +169,7 @@ internal class HttpPageLoader( try { if (page.imageUrl.isNullOrEmpty()) { page.status = Page.State.LOAD_PAGE - page.imageUrl = source.fetchImageUrl(page).awaitSingle() + page.imageUrl = source.getImageUrl(page) } val imageUrl = page.imageUrl!! diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt b/core/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt index 4cbb34812..e6eec02f4 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt @@ -58,6 +58,15 @@ fun Call.asObservable(): Observable { } } +fun Call.asObservableSuccess(): Observable { + return asObservable().doOnNext { response -> + if (!response.isSuccessful) { + response.close() + throw HttpException(response.code) + } + } +} + // Based on https://github.com/gildor/kotlin-coroutines-okhttp @OptIn(ExperimentalCoroutinesApi::class) private suspend fun Call.await(callStack: Array): Response { @@ -95,6 +104,9 @@ suspend fun Call.await(): Response { return await(callStack) } +/** + * @since extensions-lib 1.5 + */ suspend fun Call.awaitSuccess(): Response { val callStack = Exception().stackTrace.run { copyOfRange(1, size) } val response = await(callStack) @@ -105,15 +117,6 @@ suspend fun Call.awaitSuccess(): Response { return response } -fun Call.asObservableSuccess(): Observable { - return asObservable().doOnNext { response -> - if (!response.isSuccessful) { - response.close() - throw HttpException(response.code) - } - } -} - fun OkHttpClient.newCachelessCallWithProgress(request: Request, listener: ProgressListener): Call { val progressClient = newBuilder() .cache(null) diff --git a/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt b/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt index e8295a258..c87ec5cff 100644 --- a/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt +++ b/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt @@ -5,7 +5,6 @@ import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga -import tachiyomi.core.util.lang.awaitSingle import tachiyomi.core.util.lang.withIOContext import tachiyomi.domain.source.repository.SourcePagingSourceType @@ -13,19 +12,19 @@ class SourceSearchPagingSource(source: CatalogueSource, val query: String, val f source, ) { override suspend fun requestNextPage(currentPage: Int): MangasPage { - return source.fetchSearchManga(currentPage, query, filters).awaitSingle() + return source.getSearchManga(currentPage, query, filters) } } class SourcePopularPagingSource(source: CatalogueSource) : SourcePagingSource(source) { override suspend fun requestNextPage(currentPage: Int): MangasPage { - return source.fetchPopularManga(currentPage).awaitSingle() + return source.getPopularManga(currentPage) } } class SourceLatestPagingSource(source: CatalogueSource) : SourcePagingSource(source) { override suspend fun requestNextPage(currentPage: Int): MangasPage { - return source.fetchLatestUpdates(currentPage).awaitSingle() + return source.getLatestUpdates(currentPage) } } diff --git a/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt b/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt index 38d38ef57..8b5f67ef5 100644 --- a/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt +++ b/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt @@ -4,7 +4,6 @@ import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga -import rx.Observable class StubSource( override val id: Long, @@ -14,36 +13,16 @@ class StubSource( private val isInvalid: Boolean = name.isBlank() || lang.isBlank() - override suspend fun getMangaDetails(manga: SManga): SManga { + override suspend fun getMangaDetails(manga: SManga): SManga = throw SourceNotInstalledException() - } - @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getMangaDetails")) - override fun fetchMangaDetails(manga: SManga): Observable { - return Observable.error(SourceNotInstalledException()) - } - - override suspend fun getChapterList(manga: SManga): List { + override suspend fun getChapterList(manga: SManga): List = throw SourceNotInstalledException() - } - - @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getChapterList")) - override fun fetchChapterList(manga: SManga): Observable> { - return Observable.error(SourceNotInstalledException()) - } - - override suspend fun getPageList(chapter: SChapter): List { + override suspend fun getPageList(chapter: SChapter): List = throw SourceNotInstalledException() - } - @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getPageList")) - override fun fetchPageList(chapter: SChapter): Observable> { - return Observable.error(SourceNotInstalledException()) - } - - override fun toString(): String { - return if (isInvalid.not()) "$name (${lang.uppercase()})" else id.toString() - } + override fun toString(): String = + if (isInvalid.not()) "$name (${lang.uppercase()})" else id.toString() } class SourceNotInstalledException : Exception() diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/CatalogueSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/CatalogueSource.kt index f9e416def..937fa28a9 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/CatalogueSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/CatalogueSource.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.source import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import rx.Observable +import tachiyomi.core.util.lang.awaitSingle interface CatalogueSource : Source { @@ -17,30 +18,63 @@ interface CatalogueSource : Source { val supportsLatest: Boolean /** - * Returns an observable containing a page with a list of manga. + * Get a page with a list of manga. * + * @since extensions-lib 1.5 * @param page the page number to retrieve. */ - fun fetchPopularManga(page: Int): Observable + @Suppress("DEPRECATION") + suspend fun getPopularManga(page: Int): MangasPage { + return fetchPopularManga(page).awaitSingle() + } /** - * Returns an observable containing a page with a list of manga. + * Get a page with a list of manga. * + * @since extensions-lib 1.5 * @param page the page number to retrieve. * @param query the search query. * @param filters the list of filters to apply. */ - fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable + @Suppress("DEPRECATION") + suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage { + return fetchSearchManga(page, query, filters).awaitSingle() + } /** - * Returns an observable containing a page with a list of latest manga updates. + * Get a page with a list of latest manga updates. * + * @since extensions-lib 1.5 * @param page the page number to retrieve. */ - fun fetchLatestUpdates(page: Int): Observable + @Suppress("DEPRECATION") + suspend fun getLatestUpdates(page: Int): MangasPage { + return fetchLatestUpdates(page).awaitSingle() + } /** * Returns the list of filters for the source. */ fun getFilterList(): FilterList + + @Deprecated( + "Use the non-RxJava API instead", + ReplaceWith("getPopularManga"), + ) + fun fetchPopularManga(page: Int): Observable = + throw IllegalStateException("Not used") + + @Deprecated( + "Use the non-RxJava API instead", + ReplaceWith("getSearchManga"), + ) + fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable = + throw IllegalStateException("Not used") + + @Deprecated( + "Use the non-RxJava API instead", + ReplaceWith("getLatestUpdates"), + ) + fun fetchLatestUpdates(page: Int): Observable = + throw IllegalStateException("Not used") } diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt index d42885f80..e6a019ecc 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt @@ -1,6 +1,19 @@ package eu.kanade.tachiyomi.source +import android.app.Application +import android.content.SharedPreferences +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + interface ConfigurableSource : Source { + /** + * Gets instance of [SharedPreferences] scoped to the specific source. + * + * @since extensions-lib 1.5 + */ + fun getPreferences(): SharedPreferences = + Injekt.get().getSharedPreferences("source_$id", 0x0000) + fun setupPreferenceScreen(screen: PreferenceScreen) } diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt index f140eda74..83fcd7962 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt @@ -27,7 +27,7 @@ interface Source { /** * Get the updated details for a manga. * - * @since extensions-lib 1.4 + * @since extensions-lib 1.5 * @param manga the manga to update. * @return the updated manga. */ @@ -39,7 +39,7 @@ interface Source { /** * Get all the available chapters for a manga. * - * @since extensions-lib 1.4 + * @since extensions-lib 1.5 * @param manga the manga to update. * @return the chapters for the manga. */ @@ -52,7 +52,7 @@ interface Source { * Get the list of pages a chapter has. Pages should be returned * in the expected order; the index is ignored. * - * @since extensions-lib 1.4 + * @since extensions-lib 1.5 * @param chapter the chapter. * @return the pages for the chapter. */ @@ -61,41 +61,24 @@ interface Source { return fetchPageList(chapter).awaitSingle() } - /** - * Returns an observable with the updated details for a manga. - * - * @param manga the manga to update. - */ @Deprecated( "Use the non-RxJava API instead", ReplaceWith("getMangaDetails"), ) - fun fetchMangaDetails(manga: SManga): Observable = throw IllegalStateException( - "Not used", - ) + fun fetchMangaDetails(manga: SManga): Observable = + throw IllegalStateException("Not used") - /** - * Returns an observable with all the available chapters for a manga. - * - * @param manga the manga to update. - */ @Deprecated( "Use the non-RxJava API instead", ReplaceWith("getChapterList"), ) - fun fetchChapterList(manga: SManga): Observable> = throw IllegalStateException( - "Not used", - ) + fun fetchChapterList(manga: SManga): Observable> = + throw IllegalStateException("Not used") - /** - * Returns an observable with the list of pages a chapter has. Pages should be returned - * in the expected order; the index is ignored. - * - * @param chapter the chapter. - */ @Deprecated( "Use the non-RxJava API instead", ReplaceWith("getPageList"), ) - fun fetchPageList(chapter: SChapter): Observable> = Observable.empty() + fun fetchPageList(chapter: SChapter): Observable> = + throw IllegalStateException("Not used") } diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt index 5a0acc50e..957febceb 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt @@ -16,6 +16,7 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import rx.Observable +import tachiyomi.core.util.lang.awaitSingle import uy.kohesive.injekt.injectLazy import java.net.URI import java.net.URISyntaxException @@ -24,6 +25,7 @@ import java.security.MessageDigest /** * A simple implementation for sources from a website. */ +@Suppress("unused") abstract class HttpSource : CatalogueSource { /** @@ -81,6 +83,7 @@ abstract class HttpSource : CatalogueSource { * @param versionId [Int] the version ID of the source * @return a unique ID for the source */ + @Suppress("MemberVisibilityCanBePrivate") protected fun generateId(name: String, lang: String, versionId: Int): Long { val key = "${name.lowercase()}/$lang/$versionId" val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray()) @@ -202,11 +205,18 @@ abstract class HttpSource : CatalogueSource { protected abstract fun latestUpdatesParse(response: Response): MangasPage /** - * Returns an observable with the updated details for a manga. Normally it's not needed to - * override this method. + * Get the updated details for a manga. + * Normally it's not needed to override this method. * - * @param manga the manga to be updated. + * @param manga the manga to update. + * @return the updated manga. */ + @Suppress("DEPRECATION") + override suspend fun getMangaDetails(manga: SManga): SManga { + return fetchMangaDetails(manga).awaitSingle() + } + + @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getMangaDetails")) override fun fetchMangaDetails(manga: SManga): Observable { return client.newCall(mangaDetailsRequest(manga)) .asObservableSuccess() @@ -233,11 +243,23 @@ abstract class HttpSource : CatalogueSource { protected abstract fun mangaDetailsParse(response: Response): SManga /** - * Returns an observable with the updated chapter list for a manga. Normally it's not needed to - * override this method. If a manga is licensed an empty chapter list observable is returned + * Get all the available chapters for a manga. + * Normally it's not needed to override this method. * - * @param manga the manga to look for chapters. + * @param manga the manga to update. + * @return the chapters for the manga. + * @throws LicensedMangaChaptersException if a manga is licensed and therefore no chapters are available. */ + @Suppress("DEPRECATION") + override suspend fun getChapterList(manga: SManga): List { + if (manga.status == SManga.LICENSED) { + throw LicensedMangaChaptersException() + } + + return fetchChapterList(manga).awaitSingle() + } + + @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getChapterList")) override fun fetchChapterList(manga: SManga): Observable> { return if (manga.status != SManga.LICENSED) { client.newCall(chapterListRequest(manga)) @@ -268,10 +290,18 @@ abstract class HttpSource : CatalogueSource { protected abstract fun chapterListParse(response: Response): List /** - * Returns an observable with the page list for a chapter. + * Get the list of pages a chapter has. Pages should be returned + * in the expected order; the index is ignored. * - * @param chapter the chapter whose page list has to be fetched. + * @param chapter the chapter. + * @return the pages for the chapter. */ + @Suppress("DEPRECATION") + override suspend fun getPageList(chapter: SChapter): List { + return fetchPageList(chapter).awaitSingle() + } + + @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getPageList")) override fun fetchPageList(chapter: SChapter): Observable> { return client.newCall(pageListRequest(chapter)) .asObservableSuccess() @@ -301,8 +331,15 @@ abstract class HttpSource : CatalogueSource { * Returns an observable with the page containing the source url of the image. If there's any * error, it will return null instead of throwing an exception. * + * @since extensions-lib 1.5 * @param page the page whose source image has to be fetched. */ + @Suppress("DEPRECATION") + open suspend fun getImageUrl(page: Page): String { + return fetchImageUrl(page).awaitSingle() + } + + @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getImageUrl")) open fun fetchImageUrl(page: Page): Observable { return client.newCall(imageUrlRequest(page)) .asObservableSuccess() @@ -326,24 +363,14 @@ abstract class HttpSource : CatalogueSource { */ protected abstract fun imageUrlParse(response: Response): String - /** - * Returns an observable with the response of the source image. - * - * @param page the page whose source image has to be downloaded. - */ - fun fetchImage(page: Page): Observable { - // images will be cached or saved manually, so don't take up network cache - return client.newCachelessCallWithProgress(imageRequest(page), page) - .asObservableSuccess() - } - /** * Returns the response of the source image. + * Typically does not need to be overridden. * + * @since extensions-lib 1.5 * @param page the page whose source image has to be downloaded. */ - suspend fun getImage(page: Page): Response { - // images will be cached or saved manually, so don't take up network cache + open suspend fun getImage(page: Page): Response { return client.newCachelessCallWithProgress(imageRequest(page), page) .awaitSuccess() } diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt deleted file mode 100644 index 76c68e882..000000000 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt +++ /dev/null @@ -1,25 +0,0 @@ -package eu.kanade.tachiyomi.source.online - -import eu.kanade.tachiyomi.source.model.Page -import rx.Observable - -fun HttpSource.fetchAllImageUrlsFromPageList(pages: List): Observable { - return Observable.from(pages) - .filter { !it.imageUrl.isNullOrEmpty() } - .mergeWith(fetchRemainingImageUrlsFromPageList(pages)) -} - -private fun HttpSource.fetchRemainingImageUrlsFromPageList(pages: List): Observable { - return Observable.from(pages) - .filter { it.imageUrl.isNullOrEmpty() } - .concatMap { getImageUrl(it) } -} - -private fun HttpSource.getImageUrl(page: Page): Observable { - page.status = Page.State.LOAD_PAGE - return fetchImageUrl(page) - .doOnError { page.status = Page.State.ERROR } - .onErrorReturn { null } - .doOnNext { page.imageUrl = it } - .map { page } -} diff --git a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt index 403419df2..42879d559 100644 --- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt +++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt @@ -16,7 +16,6 @@ import kotlinx.serialization.json.decodeFromStream import logcat.LogPriority import nl.adaptivity.xmlutil.AndroidXmlReader import nl.adaptivity.xmlutil.serialization.XML -import rx.Observable import tachiyomi.core.metadata.comicinfo.COMIC_INFO_FILE import tachiyomi.core.metadata.comicinfo.ComicInfo import tachiyomi.core.metadata.comicinfo.copyFromComicInfo @@ -66,11 +65,11 @@ actual class LocalSource( override val supportsLatest: Boolean = true // Browse related - override fun fetchPopularManga(page: Int) = fetchSearchManga(page, "", POPULAR_FILTERS) + override suspend fun getPopularManga(page: Int) = getSearchManga(page, "", POPULAR_FILTERS) - override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS) + override suspend fun getLatestUpdates(page: Int) = getSearchManga(page, "", LATEST_FILTERS) - override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage { val baseDirsFiles = fileSystem.getFilesInBaseDirectories() val lastModifiedLimit by lazy { if (filters === LATEST_FILTERS) System.currentTimeMillis() - LATEST_THRESHOLD else 0L } var mangaDirs = baseDirsFiles @@ -143,7 +142,7 @@ actual class LocalSource( } } - return Observable.just(MangasPage(mangas.toList(), false)) + return MangasPage(mangas.toList(), false) } // Manga details related From 3d0e750519e851abbae193c2c78500ba897bf800 Mon Sep 17 00:00:00 2001 From: Joshua <49599589+joshuaxu71@users.noreply.github.com> Date: Sun, 10 Sep 2023 01:01:24 +0700 Subject: [PATCH 16/59] [Download Queue] Move series to bottom (#9918) Added item in download queue page to move series to bottom --- .../tachiyomi/ui/download/DownloadQueueScreenModel.kt | 8 ++++++-- app/src/main/res/menu/download_single.xml | 4 ++++ i18n/src/main/res/values/strings.xml | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt index 8eed7a915..18ab4c36b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt @@ -84,13 +84,17 @@ class DownloadQueueScreenModel( } reorder(newDownloads) } - R.id.move_to_top_series -> { + R.id.move_to_top_series, R.id.move_to_bottom_series -> { val (selectedSeries, otherSeries) = adapter?.currentItems ?.filterIsInstance() ?.map(DownloadItem::download) ?.partition { item.download.manga.id == it.manga.id } ?: Pair(emptyList(), emptyList()) - reorder(selectedSeries + otherSeries) + if (menuItem.itemId == R.id.move_to_top_series) { + reorder(selectedSeries + otherSeries) + } else { + reorder(otherSeries + selectedSeries) + } } R.id.cancel_download -> { cancel(listOf(item.download)) diff --git a/app/src/main/res/menu/download_single.xml b/app/src/main/res/menu/download_single.xml index 34ec33a4d..1cf14ff0c 100644 --- a/app/src/main/res/menu/download_single.xml +++ b/app/src/main/res/menu/download_single.xml @@ -13,6 +13,10 @@ android:id="@+id/move_to_bottom" android:title="@string/action_move_to_bottom" /> + + diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 9512a9f2e..b32cfa27a 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -137,6 +137,7 @@ Move to top Move series to top Move to bottom + Move series to bottom Install Share Save From 2dd2db72258f3a3d4e649ce2fcc2aee7aed951b6 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 9 Sep 2023 14:48:57 -0400 Subject: [PATCH 17/59] Update to Kotlin 1.9.10 --- .../main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt | 2 +- .../eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt | 3 ++- gradle/compose.versions.toml | 2 +- gradle/kotlinx.versions.toml | 2 +- .../kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt | 3 ++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt index 0a45187a3..c11730754 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt @@ -119,7 +119,7 @@ class Kavita(private val context: Context, id: Long) : TrackService(id, "Kavita" .reduce(Long::or) and Long.MAX_VALUE } val preferences: SharedPreferences by lazy { - context.getSharedPreferences("source_$sourceSuffixID", 0x0000) + context.getSharedPreferences("source_$sourceSuffixID", Context.MODE_PRIVATE) } val prefApiUrl = preferences.getString("APIURL", "")!! if (prefApiUrl.isEmpty()) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt index 24127c63a..86227095d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.data.track.suwayomi import android.app.Application +import android.content.Context import android.content.SharedPreferences import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.TrackManager @@ -107,7 +108,7 @@ class TachideskApi { } private val preferences: SharedPreferences by lazy { - Injekt.get().getSharedPreferences("source_$tachideskExtensionId", 0x0000) + Injekt.get().getSharedPreferences("source_$tachideskExtensionId", Context.MODE_PRIVATE) } private fun getPrefBaseUrl(): String = preferences.getString(ADDRESS_TITLE, ADDRESS_DEFAULT)!! diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index e21536263..dc18de785 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,5 +1,5 @@ [versions] -compiler = "1.5.2" +compiler = "1.5.3" compose-bom = "2023.09.00-alpha02" accompanist = "0.33.1-alpha" diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index 61d4968c4..be52d57f9 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -1,5 +1,5 @@ [versions] -kotlin_version = "1.9.0" +kotlin_version = "1.9.10" serialization_version = "1.6.0" xml_serialization_version = "0.86.1" diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt index e6a019ecc..4be411e3b 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.source import android.app.Application +import android.content.Context import android.content.SharedPreferences import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -13,7 +14,7 @@ interface ConfigurableSource : Source { * @since extensions-lib 1.5 */ fun getPreferences(): SharedPreferences = - Injekt.get().getSharedPreferences("source_$id", 0x0000) + Injekt.get().getSharedPreferences("source_$id", Context.MODE_PRIVATE) fun setupPreferenceScreen(screen: PreferenceScreen) } From 36f1e0e47648ca8745ee5f80b54b432a82dc0edf Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sat, 9 Sep 2023 20:51:54 +0200 Subject: [PATCH 18/59] Translations update from Hosted Weblate (#9904) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Weblate translations Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ar/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cs/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/it/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ja/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/lv/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pl/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sr/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/th/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/vi/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/ Translation: Tachiyomi/Tachiyomi 0.x Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> Co-authored-by: Ali Aljishi Co-authored-by: Astrid Co-authored-by: C201 Co-authored-by: Clxff H3r4ld0 <123844876+clxf12@users.noreply.github.com> Co-authored-by: DarKCroX Co-authored-by: Dexroneum Co-authored-by: Druvvaldis Co-authored-by: Eduard Ereza Martínez Co-authored-by: Giorgio Sanna Co-authored-by: ID-86 Co-authored-by: InfinityDouki56 Co-authored-by: Jozef Hollý Co-authored-by: Karuto Co-authored-by: Luna Jernberg Co-authored-by: Lyfja Co-authored-by: Milo Ivir Co-authored-by: Paavalen Lingachetti Co-authored-by: Pitpe11 Co-authored-by: Stefan Rackov Co-authored-by: Swyter Co-authored-by: Uzuki Shimamura Co-authored-by: ZiomaleQ Co-authored-by: abc0922001 Co-authored-by: altinat Co-authored-by: orkan gökçe alaz aşina Co-authored-by: sebastians17 --- i18n/src/main/res/values-am/strings.xml | 2 - i18n/src/main/res/values-ar/strings.xml | 9 +-- i18n/src/main/res/values-b+es+419/strings.xml | 2 - i18n/src/main/res/values-be/strings.xml | 2 - i18n/src/main/res/values-bg/strings.xml | 2 - i18n/src/main/res/values-bn/strings.xml | 2 - i18n/src/main/res/values-ca/strings.xml | 18 +++-- i18n/src/main/res/values-ceb/strings.xml | 2 - i18n/src/main/res/values-cs/strings.xml | 9 +-- i18n/src/main/res/values-cv/strings.xml | 26 +++--- i18n/src/main/res/values-da/strings.xml | 2 - i18n/src/main/res/values-de/strings.xml | 9 +-- i18n/src/main/res/values-el/strings.xml | 11 ++- i18n/src/main/res/values-eo/strings.xml | 2 - i18n/src/main/res/values-es/strings.xml | 18 ++--- i18n/src/main/res/values-eu/strings.xml | 2 - i18n/src/main/res/values-fa/strings.xml | 2 - i18n/src/main/res/values-fi/strings.xml | 2 - i18n/src/main/res/values-fil/strings.xml | 18 +++-- i18n/src/main/res/values-fr/strings.xml | 39 ++++++--- i18n/src/main/res/values-gl/strings.xml | 2 - i18n/src/main/res/values-he/strings.xml | 12 ++- i18n/src/main/res/values-hi/strings.xml | 2 - i18n/src/main/res/values-hr/strings.xml | 12 +-- i18n/src/main/res/values-hu/strings.xml | 2 - i18n/src/main/res/values-in/strings.xml | 16 ++-- i18n/src/main/res/values-it/strings.xml | 9 +-- i18n/src/main/res/values-ja/strings.xml | 9 +-- i18n/src/main/res/values-jv/strings.xml | 2 - i18n/src/main/res/values-ka-rGE/strings.xml | 2 - i18n/src/main/res/values-kk/strings.xml | 2 - i18n/src/main/res/values-km/strings.xml | 2 - i18n/src/main/res/values-kn/strings.xml | 2 - i18n/src/main/res/values-ko/strings.xml | 2 - i18n/src/main/res/values-lt/strings.xml | 2 - i18n/src/main/res/values-lv/strings.xml | 81 ++++++++++++++----- i18n/src/main/res/values-mr/strings.xml | 2 - i18n/src/main/res/values-ms/strings.xml | 9 +-- i18n/src/main/res/values-nb-rNO/strings.xml | 2 - i18n/src/main/res/values-ne/strings.xml | 2 - i18n/src/main/res/values-nl/strings.xml | 76 ++++++++++++++++- i18n/src/main/res/values-nn/strings.xml | 2 - i18n/src/main/res/values-pl/strings.xml | 36 ++++++--- i18n/src/main/res/values-pt-rBR/strings.xml | 14 ++-- i18n/src/main/res/values-pt/strings.xml | 2 - i18n/src/main/res/values-ro/strings.xml | 2 - i18n/src/main/res/values-ru/strings.xml | 17 ++-- i18n/src/main/res/values-sa/strings.xml | 2 - i18n/src/main/res/values-sah/strings.xml | 2 - i18n/src/main/res/values-sc/strings.xml | 2 - i18n/src/main/res/values-sdh/strings.xml | 2 - i18n/src/main/res/values-sk/strings.xml | 2 - i18n/src/main/res/values-sq/strings.xml | 2 - i18n/src/main/res/values-sr/strings.xml | 16 ++-- i18n/src/main/res/values-sv/strings.xml | 9 +-- i18n/src/main/res/values-te/strings.xml | 2 - i18n/src/main/res/values-th/strings.xml | 12 +-- i18n/src/main/res/values-tr/strings.xml | 19 +++-- i18n/src/main/res/values-uk/strings.xml | 2 - i18n/src/main/res/values-uz/strings.xml | 2 - i18n/src/main/res/values-vi/strings.xml | 3 +- i18n/src/main/res/values-zh-rCN/strings.xml | 2 - i18n/src/main/res/values-zh-rTW/strings.xml | 13 ++- 63 files changed, 333 insertions(+), 261 deletions(-) diff --git a/i18n/src/main/res/values-am/strings.xml b/i18n/src/main/res/values-am/strings.xml index 566ebf712..60b800dd0 100644 --- a/i18n/src/main/res/values-am/strings.xml +++ b/i18n/src/main/res/values-am/strings.xml @@ -143,8 +143,6 @@ ማጣሪያ ምናሌ ማስተካከያዎች - ለመውጣት እንደገና ተመልሰው ይጫኑ - ታቺዮሚን ይክፈቱ ኢክስቴንሽኖች ታሪክ መከታተል diff --git a/i18n/src/main/res/values-ar/strings.xml b/i18n/src/main/res/values-ar/strings.xml index 29e1cf007..b6a544028 100644 --- a/i18n/src/main/res/values-ar/strings.xml +++ b/i18n/src/main/res/values-ar/strings.xml @@ -251,7 +251,7 @@ إضافة ذات ريبة هذه اﻹضافة موقَّعة بشهادة ذات ريبة ولم تفعَّل. \n -\nيمكن لأي إضافة خبيثة قراءة بيانات اعتماد تسجيل الدخول المخزَّنة في Tachiyomi أو تنفيذ تعليمات برمجية عشوائية. +\nيمكن لأي إضافة خبيثة قراءة بيانات اعتماد تسجيل الدخول المخزَّنة أو تنفيذ تعليمات برمجية عشوائية. \n \nأنت تقبل هذه المخاطر إن وثقت بالشهادة. سرعة مؤثر النقر المزدوج @@ -297,7 +297,6 @@ تحديث المكتبة المزيد - افتح Tachiyomi نقل إلى الأعلى الأقدم الأَحدثْ @@ -346,11 +345,10 @@ إلغاء التثبيت تثبيت عكس التحديد - اضغط رجوع مرة أخرى للخروج تحديثات اﻹضافات تحديثات الفصول يرجى تحديث تطبيق WebView لتوافق أفضل - يتطلب Tachiyomi وجود WebView + إن وجود WebView لازم ليعمل التطبيق فشل في تجاوز Cloudflare لايوجد تحديث للإضافة @@ -441,7 +439,7 @@ النسخة الإحتياطية لا تحتوي على أيّة إدخالات المكتبة. ملفُّ النسخ الاحتياطيِّ غير صالح مزامنة أحاديّة لتحديث تقدم الفصول في خدمات التتبع. قم بإعداد التتبع الخاص للإدخالات محدّدة من زر التتبع الخاص بها. - هذه الإضافة ليست من قائمة إضافات Tachiyomi الرسمية. + ليست هذه الإضافة من القائمة الرسمية. غير رسمي تحقق من وجود غلاف جديد وتفاصيل جديدة عند تحديث المكتبة تحديث البيانات الوصفية تلقائياً @@ -882,4 +880,5 @@ لا اتصال بالإنترنت خطأ HTTP %d، انظر في WebView لم نصل %s + افتح %s \ No newline at end of file diff --git a/i18n/src/main/res/values-b+es+419/strings.xml b/i18n/src/main/res/values-b+es+419/strings.xml index 8d6454cdf..ede476a22 100644 --- a/i18n/src/main/res/values-b+es+419/strings.xml +++ b/i18n/src/main/res/values-b+es+419/strings.xml @@ -5,7 +5,6 @@ Capítulo más reciente Total de capítulos Información de la extensión - Pulse Atrás de nuevo para salir Copia de seguridad y restauración Historial Historial @@ -38,7 +37,6 @@ Filtrar Menú Configuración - Desbloquear Tachiyomi Capítulos Manga Categorías diff --git a/i18n/src/main/res/values-be/strings.xml b/i18n/src/main/res/values-be/strings.xml index d9d7ec4bb..1cefa0e7b 100644 --- a/i18n/src/main/res/values-be/strings.xml +++ b/i18n/src/main/res/values-be/strings.xml @@ -69,8 +69,6 @@ Фільтр Меню Налады - Націсніце назад яшчэ раз, каб выйсці - Разблакіраваць Tachiyomi Дапамога Інфармацыя аб пашырэнні Назва diff --git a/i18n/src/main/res/values-bg/strings.xml b/i18n/src/main/res/values-bg/strings.xml index 63af6b664..097115845 100644 --- a/i18n/src/main/res/values-bg/strings.xml +++ b/i18n/src/main/res/values-bg/strings.xml @@ -428,8 +428,6 @@ Избери обратно Последна глава Меню - Натиснете назад още веднъж, за да излезете - Отключете Тачийоми Източници Още Режим на четене diff --git a/i18n/src/main/res/values-bn/strings.xml b/i18n/src/main/res/values-bn/strings.xml index e1f212a9e..7f3dc3ef9 100644 --- a/i18n/src/main/res/values-bn/strings.xml +++ b/i18n/src/main/res/values-bn/strings.xml @@ -307,8 +307,6 @@ তারিখে যোগকৃত সর্বশেষ অধ্যায় তালিকা - প্রস্থান করতে আবার ব্যাক চাপুন - তাচিওমি খুলুন উৎস সমূহ আরও প্রদর্শন diff --git a/i18n/src/main/res/values-ca/strings.xml b/i18n/src/main/res/values-ca/strings.xml index 4535a3a38..033783918 100644 --- a/i18n/src/main/res/values-ca/strings.xml +++ b/i18n/src/main/res/values-ca/strings.xml @@ -99,7 +99,7 @@ Extensió no fiable Aquesta extensió s’ha signat amb un certificat que no és de confiança i no s’ha activat. \n -\nUna extensió maliciosa podria llegir qualsevol credencial desada al Tachiyomi o executar codi arbitrari. +\nUna extensió maliciosa podria llegir qualsevol credencial d’inici de sessió desada o executar codi arbitrari. \n \nSi confieu en aquest certificat, accepteu aquests riscos. Pantalla completa @@ -326,9 +326,8 @@ Actualitzacions pendents Mostra el contingut a l’àrea de retall No s’ha pogut evitar el Cloudflare - Actualitzeu l’aplicació de WebView per a tenir més bona compatibilitat + Actualitzeu l’aplicació WebView per a tenir més bona compatibilitat Novetats de capítols - Desbloca el Tachiyomi El mode discret amaga el contingut de l’aplicació en canviar entre aplicacions i bloca les captures de pantalla Visualització @@ -376,12 +375,11 @@ Desfixa A la biblioteca Afegeix a la biblioteca - El Tachiyomi requereix el WebView + La WebView és necessària per al funcionament de l’aplicació Menys Més Llicències de codi obert Lloc web - Torneu a prémer Endarrere per a sortir Només els baixats Cap. %1$s - %2$s Ha fallat la restauració de la còpia de seguretat @@ -413,7 +411,7 @@ La sincronització és unidireccional per a actualitzar el progrés dels capítols als serveis de seguiment. Configureu el seguiment d’elements individuals al seu botó de seguiment. Refresca les portades de la biblioteca - Aquesta extensió no pertany a la llista d’extensions oficials del Tachiyomi. + Aquesta extensió no pertany a la llista d’extensions oficials. No oficial Per data de pujada Dades @@ -648,8 +646,8 @@ S’ha produït un error en desar la imatge No hi ha cap element a la biblioteca del qual fer còpia de seguretat Hi ha una nova versió disponible als llançaments oficials. Premeu per a obtenir informació de com migrar a partir dels llançaments no oficials d’F-Droid. - Neteja les dades del WebView - S’han netejat les dades del WebView + Neteja les dades de la WebView + S’han netejat les dades de la WebView Tanca No s’ha trobat cap font instal·lada No s’ha trobat cap font @@ -815,4 +813,8 @@ Inici de sessió al seguiment S’ha invalidat l\'índex de baixades Premeu aquí per a obtenir ajuda amb el Cloudflare + Desbloca %s + No hi ha connexió a Internet + HTTP %d, comproveu el lloc web en una WebView + No s’ha pogut accedir a %s \ No newline at end of file diff --git a/i18n/src/main/res/values-ceb/strings.xml b/i18n/src/main/res/values-ceb/strings.xml index e613ada67..81529b94c 100644 --- a/i18n/src/main/res/values-ceb/strings.xml +++ b/i18n/src/main/res/values-ceb/strings.xml @@ -2,9 +2,7 @@ Kasaysayan Mga update - I-unlock ang Tachiyomi Panghimatuod aron makumpirma ang pagbag-o - Pindota balik pag-usab aron makagawas Mga setting Menu Gi-bookmark diff --git a/i18n/src/main/res/values-cs/strings.xml b/i18n/src/main/res/values-cs/strings.xml index c4579eee4..49b800e0f 100644 --- a/i18n/src/main/res/values-cs/strings.xml +++ b/i18n/src/main/res/values-cs/strings.xml @@ -63,7 +63,7 @@ Nedůvěryhodné rozšíření Toto rozšíření bylo podepsané nedůvěryhodným certifikátem a nebylo aktivované. \n -\nŠkodlivé rozšíření může přečíst přihlašovací údaje uložené v Tachiyomi nebo spustit libovolný kód. +\nŠkodlivé rozšíření může přečíst jakékoliv uložené přihlašovací údaje nebo spustit libovolný kód. \n \nDůvěřováním tomuto certifikátu přijímáte tato rizika. Celá obrazovka @@ -324,7 +324,6 @@ Nejnovější Zobrazit kapitoly Poslední kapitola - Odemknout Tachiyomi Přidat sledování Nebyly nalezeny žádné kapitoly Nastavit jako výchozí @@ -408,7 +407,7 @@ Žádné Zdroje z tohoto rozšíření mohou obsahovat NSFW (18+) obsah 18+ - Toto rozšíření není z oficiálního seznamu rozšíření pro Tachiyomi. + Toto rozšíření není z oficiálního seznamu rozšíření. Neoficiální %d kategorie @@ -444,7 +443,7 @@ Postup Výchozí nastavení kapitol aktualizováno Prosím aktualizujte aplikaci WebView pro lepší kompatibilitu - Je nutné mít nainstalovanou aplikaci WebView + Je nutné mít nainstalovanou aplikaci WebView pro správné fungování aplikace Nastala chyba při obcházení služby Cloudflare Je dostupná aktualizace rozšíření @@ -498,7 +497,6 @@ Nastavení vyhledávání Datum přidání Sledováno - Opětovným stisknutím tlačítka aplikaci opustíte Režim čtení Ukazovat režim čtení Pro tuto sérii @@ -834,4 +832,5 @@ Bez připojení k internetu Nelze dosáhnout %s HTTP %d, zkontrolovat web v WebView + Odemknout %s \ No newline at end of file diff --git a/i18n/src/main/res/values-cv/strings.xml b/i18n/src/main/res/values-cv/strings.xml index 24f71c2fa..4e43a567a 100644 --- a/i18n/src/main/res/values-cv/strings.xml +++ b/i18n/src/main/res/values-cv/strings.xml @@ -11,7 +11,7 @@ Юлашки вуланӑ сыпăк Сӳнтернӗ Вуланӑ хыҫҫӑн - Тиев вырӑнӗ + Тийев вырӑнӗ Вулани Кӑвак Симӗс @@ -27,7 +27,7 @@ Хура Шурӑ Ӳкерчĕк хыҫӑн тӗсӗ - Экран + Екран Хутлани Катерт Лартнӑ @@ -100,7 +100,6 @@ Пухмӑш хуш Хуш Умӗнхине вуланӑ пек паллӑ ту - Тухма тепӗр хут пус Улӑштар Пурне те сӳнтер Пурне те ҫут @@ -135,7 +134,7 @@ Wi-Fi ҫыхӑну ҫук Йӑнӑш Ҫӗнӗ версси пур! - Тиев йӑнӑшӗ + Тийев йӑнӑшӗ Тиенсе пӗтрӗ %1$s-мӗш сыпӑк Ҫӗнӗ сыпӑксем тупӑнман @@ -154,7 +153,6 @@ Меллӗ сетке Ҫӑтӑ сетке Тепӗр майлӑ суйла - Tachiyomi уҫ Сӳнтернӗ Сетке пысӑкӑшӗ Урлӑ @@ -220,11 +218,11 @@ Ҫаклатнӑ урлӑскер Ирӗклӗ Яланхилле урлӑ-тӑрӑх - Энимсӗр + Енимсӗр Пысӑклатни пуҫламӑш тӑрӑмӗ Тӑнлӑ Тӑс - Экранпа + Екранпа Сарӑмлани Вӗҫӗмсӗрех урлӑ Вӑрӑм елсем @@ -238,7 +236,7 @@ Куҫӑм Аланӑ сыпӑксене сиктермелле Вуланӑ сыпӑксене сиктермелле - Экрана ҫутӑ тыт + Екрана ҫутӑ тыт Тӗттӗмлетӳ Ҫутату Витӗм @@ -279,15 +277,15 @@ Хушмасен ҫӗнетӗвӗсем Сыпӑксен ҫӗнетӗвӗсем Яланхи - Тиеве вӑхӑтлӑха чарнӑ + Тийеве вӑхӑтлӑха чарнӑ Кӗтмен йӑнӑша пула сыпӑксене тиесе илеймест - Тиевҫӗ + Тийевҫӗ Tachiyomi валли WebView кирлӗ Хушма валли ҫӗнетӳ пур %d хушма валли ҫӗнетӳ пур - Тиев… + Тийев… Ҫӗнетӳсем тупӑнман Тиесе ил Хуплашка суйла @@ -308,7 +306,7 @@ Ҫӗнӗ сыпӑксем %d хайлав валли тупӑннӑ Ҫӗнӗ сыпӑксен пуррине тӗрӗслени - Сыпӑксене тиесе илес ҫук. Тиевсем пайӗнче ҫӗнӗрен хӑтланса пӑхма пултаратӑн + Сыпӑксене тиесе илес ҫук. Тийевсем пайӗнче ҫӗнӗрен хӑтланса пӑхма пултаратӑн Ӑтавла Куҫар Куҫарма ҫӑл куҫ суйла @@ -349,7 +347,7 @@ Пӑрахнӑ Вӗҫленӗ Вулатӑп - Эсӗ суйланӑ сыпӑксене катертесшӗнех-и\? + Есӗ суйланӑ сыпӑксене катертесшӗнех-и\? Вуламанине Тиесе ил Тиенӗ вӑхӑчӗпе @@ -395,7 +393,7 @@ Тӗрӗс мар янтӑв файлӗ Пухмӑша ҫӗнетни Паллӑ мар йӑнӑш - Эсӗ тухрӑн + Есӗ тухрӑн Тух “%1$s тухмалла-и\? Ӑнӑҫлӑ кӗни diff --git a/i18n/src/main/res/values-da/strings.xml b/i18n/src/main/res/values-da/strings.xml index 9124fb10a..ccd1e3144 100644 --- a/i18n/src/main/res/values-da/strings.xml +++ b/i18n/src/main/res/values-da/strings.xml @@ -7,7 +7,6 @@ Migerering Standard Advarsel - Lås op for Tachiyomi Bogmærket Fjern filter Inverter valg @@ -46,7 +45,6 @@ Intet læst for nyligt Ingen downloads Dato hentet - Tryk tilbage igen for at afslutte Indstillinger Ulæst Manga ialt diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml index 6e7b2d728..44b84fdc5 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -249,7 +249,7 @@ Deinstallieren Diese Erweiterung ist mit einem nicht vertrauenswürdigen Zertifikat unterschrieben und wurde nicht aktiviert. \n -\nEine bösartige Erweiterung könnte in Tachiyomi gespeicherte Anmeldedaten auslesen oder einen schädlichen Code ausführen. +\nEine bösartige Erweiterung könnte gespeicherte Anmeldedaten auslesen oder einen schädlichen Code ausführen. \n \nDurch das Vertrauen dieses Zertifikats akzeptierst du diese Risiken. Keine Animation @@ -328,7 +328,6 @@ Fehler beim Umgehen von Cloudflare Bitte aktualisiere die WebView-App für eine bessere Kompatibilität Kapitelaktualisierungen - Tachiyomi entsperren Sicherer Bildschirm verbirgt App-Inhalte beim Wechseln von Apps und blockiert Screenshots Anzeige @@ -378,8 +377,7 @@ Mehr In der Bibliothek Zur Bibliothek hinzufügen - Zum Beenden nochmal die Zurück-Taste drücken - WebView ist für Tachiyomi erforderlich + WebView ist für das Funktionieren der App erforderlich Open-Source-Lizenzen Webseite Nur Heruntergeladenes @@ -413,7 +411,7 @@ Einweg-Synchronisation zum Aktualisieren der Kapitelfortschritte in den Trackingdiensten. Richte Tracking für einzelne Einträge über deren jeweiligen Tracking-Button ein. Bibliothekscover aktualisieren - Diese Erweiterung stammt nicht von der offiziellen Tachiyomi-Erweiterungsliste. + Diese Erweiterung stammt nicht aus der offiziellen Liste. Inoffiziell Nach Uploaddatum Daten @@ -818,4 +816,5 @@ HTTP %d, überprüfe die Webseite in WebView Keine Internetverbindung %s konnte nicht erreicht werden + %s entsperren \ No newline at end of file diff --git a/i18n/src/main/res/values-el/strings.xml b/i18n/src/main/res/values-el/strings.xml index 446f90670..5a8f8939c 100644 --- a/i18n/src/main/res/values-el/strings.xml +++ b/i18n/src/main/res/values-el/strings.xml @@ -97,9 +97,9 @@ Μη αξιόπιστο Απεγκατάσταση Μη αξιόπιστη επέκταση - Αυτή η επέκταση υπογράφηκε με μη αξιόπιστο πιστοποιητικό και δεν ενεργοποιήθηκε. + Αυτή η επέκταση υπογράφηκε με αναξιόπιστο πιστοποιητικό και δεν ενεργοποιήθηκε. \n -\nΜια κακόβουλη επέκταση θα μπορούσε να διαβάσει τα διαπιστευτήρια σύνδεσης που είναι αποθηκευμένα στο Tachiyomi ή να εκτελέσει αυθαίρετο κώδικα. +\nΜια κακόβουλη επέκταση θα μπορούσε να διαβάσει τυχόν αποθηκευμένα διαπιστευτήρια σύνδεσης ή να εκτελέσει αυθαίρετο κώδικα. \n \nΕμπιστεύοντας αυτό το πιστοποιητικό αποδέχεστε αυτούς τους κινδύνους. Πλήρης οθόνη @@ -302,13 +302,12 @@ Χρησιμοποιήθηκε τελευταία Προσθήκη tracking Καρφιτσωμένα - Πατήστε ξανά για έξοδο %02d λεπτά, %02d δευτερόλεπτα Επιλογή αντίστροφου Ενημερώσεις επεκτάσεων Ενημερώσεις κεφαλαίων Παρακαλώ ενημερώστε την εφαρμογή WebView για καλύτερη συμβατότητα - Το WebView απαιτείται για το Tachiyomi + Το WebView απαιτείται για τη λειτουργία της εφαρμογής Κεφάλαιο %1$s και %2$d ακόμη Κεφάλαια %1$s Κεφάλαιο %1$s @@ -384,7 +383,6 @@ Προβολή κεφαλαίων Νεότερο κεφάλαιο Μενού - Ξεκλειδώστε το Tachiyomi Ληφθέντα μόνο Πηγές Παλαιότερο @@ -413,7 +411,7 @@ Μονόδρομος συγχρονισμός για ενημέρωση των υπηρεσιών παρακολούθησης προόδου κεφαλαίων. Ρυθμίστε την παρακολούθηση για μεμονωμένες καταχωρήσεις από το κουμπί παρακολούθησης τους. Ανανέωση εξώφυλλων βιβλιοθήκης - Αυτή η επέκταση δεν προέρχεται από την επίσημη λίστα επεκτάσεων Tachiyomi. + Αυτή η επέκταση δεν προέρχεται από την επίσημη λίστα. Ανεπίσημη Από ημερομηνία μεταφόρτωσης Δεδομένα @@ -818,4 +816,5 @@ Δεν μπορούσε να φτάσει το %s HTTP %d, ελέγξτε την ιστοσελίδα στο WebView Δεν υπάρχει σύνδεση στο διαδίκτυο + Ξεκλείδωμα %s \ No newline at end of file diff --git a/i18n/src/main/res/values-eo/strings.xml b/i18n/src/main/res/values-eo/strings.xml index 22954687f..857703896 100644 --- a/i18n/src/main/res/values-eo/strings.xml +++ b/i18n/src/main/res/values-eo/strings.xml @@ -47,7 +47,6 @@ Filtrilo Menuo Agordoj - Malŝlosi Tachiyomi-n Historio Ĉapitroj Biblioteka kontribuoj @@ -448,7 +447,6 @@ Meznokta Vesperiĝo Ŝargas… Nuligi ĉiujn por ĉi tiu serio - Premi «reen» denove por eliri Aŭtentigi por konfirmi ŝanĝon Rezignita restaŭro Restaŭro fiaskis diff --git a/i18n/src/main/res/values-es/strings.xml b/i18n/src/main/res/values-es/strings.xml index 7ecdab79d..eda92c287 100644 --- a/i18n/src/main/res/values-es/strings.xml +++ b/i18n/src/main/res/values-es/strings.xml @@ -60,7 +60,7 @@ Cada 2 días Restricciones de actualización automática del dispositivo Mientras se carga la batería - Series completadas + Marcadas como completadas Actualizar progreso al terminar un capítulo Pantalla completa @@ -292,7 +292,7 @@ Copiar Esta extensión está firmada por una fuente sin certificar y por lo tanto no se ha activado. \n -\nUna extensión maliciosa puede leer credenciales de inicio guardadas en Tachiyomi o ejecutar cualquier tipo de código en tu dispositivo. +\nUna extensión maliciosa puede leer credenciales de inicio guardadas o ejecutar cualquier tipo de código en tu dispositivo. \n \nAl confiar en este certificado aceptas estos riesgos. Sin animación @@ -361,7 +361,6 @@ Fallo al evitar Cloudflare Actualiza la aplicación WebView para mejorar la compatibilidad Nuevos capítulos - Desbloquear Tachiyomi Pantalla segura oculta el contenido al cambiar de aplicación y bloquea las capturas de pantalla Visualización @@ -413,12 +412,11 @@ Añadir seguimiento En biblioteca Añadir a biblioteca - Tachiyomi necesita WebView + Primero instala WebView para poder ver contenido de la aplicación Menos Más Licencias de código abierto Página web - Pulsa atrás de nuevo para salir Sólo ya descargados Caps. %1$s-%2$s Se ha cancelado la restauración @@ -453,7 +451,7 @@ Completada en %1$s con %2$s errores La sincronización de estos servicios solo funciona en un solo sentido. Cada elemento en tu biblioteca tiene un botón de seguimiento y tendrás que configurarlo a mano, uno a uno. - Esta extensión no es de la lista oficial de extensiones de Tachiyomi. + Esta extensión no es de la lista oficial de extensiones. No oficial Datos Fuentes que faltan: @@ -676,8 +674,8 @@ Desplazarse por el resto de la página antes de cambiar Cuadrícula sólo de portadas Acercar la vista en horizontal - Series sin empezar - Omitido porque la serie está completa + Sin empezar + Omitido, ya que su publicación ha terminado Omitido porque hay capítulos sin leer Omitido porque no hay capítulos leídos Ver más detalles @@ -748,7 +746,7 @@ Populares Varios idiomas No se han concedido los permisos de almacenamiento - Saltando, porque este manga no necesita actualizarse + Omitido, ya que no es necesario actualizarse Buscar… Sincroniza tu progreso de lectura; unidireccional o mejorada Descargas automáticas y por adelantado @@ -865,4 +863,6 @@ No se ha podido acceder a %s HTTP %d, comprueba la página web en WebView Sin conexión a Internet + Desbloquear %s + Mover al último puesto \ No newline at end of file diff --git a/i18n/src/main/res/values-eu/strings.xml b/i18n/src/main/res/values-eu/strings.xml index 8a944d45f..77162b700 100644 --- a/i18n/src/main/res/values-eu/strings.xml +++ b/i18n/src/main/res/values-eu/strings.xml @@ -482,9 +482,7 @@ Gehienezko babeskopiak Alfabetikoki Oharra - Desblokeatu Tachiyomi Autentifikatu aldaketa berresteko - Sakatu atzera berriro irteteko Ezarpenak Menua Iragazi diff --git a/i18n/src/main/res/values-fa/strings.xml b/i18n/src/main/res/values-fa/strings.xml index 415366568..cb38c0439 100644 --- a/i18n/src/main/res/values-fa/strings.xml +++ b/i18n/src/main/res/values-fa/strings.xml @@ -97,7 +97,6 @@ Dodge / Lighten هر ۱۲ ساعت یکبار انتخاب دسته بندی - بازکردن تاچی یومی هیچ دسته بندی وجود ندارد. با زدن دکمه به علاوه دسته بندی جدیدی بسازید. کتابخانه شما خالی است هیچ چیز مانگاای به تازگی خوانده شده @@ -427,7 +426,6 @@ فیلتر منو تنضیمات - برای بستن دکمه بازگشت را یک بار دیگر بزنید تاریخچه قسمت ها کتابخانه ورودی‌ها diff --git a/i18n/src/main/res/values-fi/strings.xml b/i18n/src/main/res/values-fi/strings.xml index 256bf4abf..c97467e5f 100644 --- a/i18n/src/main/res/values-fi/strings.xml +++ b/i18n/src/main/res/values-fi/strings.xml @@ -323,7 +323,6 @@ Cloudflaren ohittaminen epäonnistui Lukujen päivitykset - Avaa Tachiyomi Näyttö Päivitettävät Päivitä WebView-sovellus yhteensopivuuden parantamiseksi @@ -367,7 +366,6 @@ Varmuuskopion palautus epäonnistui Varmuuskopiointi epäonnistui Ohita suodatetut luvut - Paina takaisin uudestaan poistuaksesi Ladatut Lähteet Päivittää kirjastoa diff --git a/i18n/src/main/res/values-fil/strings.xml b/i18n/src/main/res/values-fil/strings.xml index 2625e1750..e1292a666 100644 --- a/i18n/src/main/res/values-fil/strings.xml +++ b/i18n/src/main/res/values-fil/strings.xml @@ -69,8 +69,6 @@ Pansala Menu Mga setting - Pindutin muli para umalis - Buksan ang Tachiyomi Nakaraan Tina-track Mga Kabanata @@ -124,7 +122,7 @@ Pinili kong lugar Pagkamarkahang nabasa na Pagkatapos basahin, kusang burahin - Lugar ng paglalagyan + Lokasyon sa pag-download Kapal ng gilid Pagbabasa Ipakita palagi ang paglipat-kabanata @@ -187,11 +185,11 @@ I-animate ang paglipat-pahina Ipakita ang laman sa cutout area Naka-fullscreen - Wala sa opisyal na listahan ng mga extension ng Tachiyomi ang extension na ito. + Wala sa opisyal na listahan ang extension na ito. Hindi na available ang extension na ito. Maaaring hindi ito gumana nang maayos at maaaring magdulot ng mga isyu sa app. Inirerekomenda ang pag-uninstall nito. Pinirmahan ang extension na ito gamit ang isang kaduda-dudang certificate at hindi muna pinagana. \n -\nMaaaring mabasa ng isang kaduda-dudang extension ang kahit anong credentials sa pag-login na nakatago sa Tachiyomi o di kaya nama\'y magsimula ng delikadong code. +\nMaaaring mabasa ng isang kaduda-dudang extension ang kahit anong nakatagong credentials sa pag-login o di kaya nama\'y magsimula ng delikadong code. \n \nTinatanggap mo ang mga bantang ito sa pagtiwala sa certificate na ito. Kaduda-dudang extension @@ -271,7 +269,7 @@ Nagka-error Taga-download Paki-update po ang WebView app para sa mas maayos na paggana - Kailangan ng Tachiyomi ang WebView + Kinakailangan ng app ang WebView upang gumana ito Bigong ma-bypass ang Cloudflare Ang extension ay available upang i-update @@ -696,7 +694,7 @@ Sigurado ka ba\? Susunod na hindi pa nababasa na kabanata - Susunod na ang %d na hindi pa nababasa na kabanata + Susunod na %d di pa nababasa na kabanata Marami Tatanggalin mo na ang \"%s\" mula sa aklatan mo @@ -800,7 +798,7 @@ Itakdang i-update bawat Sa labas ng inaasahang release period Mga pagitan - I-customize ang Interval + Ayusin ang interval Nilaktawan dahil walang inaasahang release ngayong araw May mga resulta Tanggalin ang na-download @@ -815,4 +813,8 @@ Hindi makalikha ng backup file Pag-login sa tracking Lisensyado - Walang mapakitang kabanata + I-unlock ang %s + Walang koneksyon sa Internet + HTTP %d, tignan ang website sa WebView + Hindi maabot ang %s \ No newline at end of file diff --git a/i18n/src/main/res/values-fr/strings.xml b/i18n/src/main/res/values-fr/strings.xml index f99cf6f4f..6f1d9e714 100644 --- a/i18n/src/main/res/values-fr/strings.xml +++ b/i18n/src/main/res/values-fr/strings.xml @@ -282,7 +282,7 @@ Extension non reconnue Cette extension a été signée avec un certificat non fiable et n\'a pas été activée. \n -\nUne extension malveillante pourrait lire n\'importe quel identifiant de connexion stocké dans Tachiyomi ou exécuter un code arbitraire. +\nUne extension malveillante pourrait lire n\'importe quel identifiant de connexion stocké ou exécuter un code arbitraire. \n \nEn faisant confiance à ce certificat, vous acceptez ces risques. Vitesse d\'animation du double-clic @@ -313,7 +313,7 @@ Échec du chargement des pages : %1$s Déplacer Copier - Afficher en cas d\'appui long + Afficher les actions en appuyant longuement Ouvrir dans WebView Couleurs à 32 bits Passer les chapitres marqués comme lus @@ -363,7 +363,6 @@ Impossible de contourner Cloudflare Veuillez mettre à jour l\'application WebView pour une meilleure compatibilité Mises à jour des chapitres - Débloquer Tachiyomi L\'écran sécurisé cache le contenu lors du changement d\'application et bloque les captures d\'écran Affichage @@ -426,11 +425,10 @@ Site web Ch. %1$s – %2$s Licences à code source ouvert - Appuyer à nouveau pour quitter Dernière utilisée Rechercher des mises à jour %02d min, %02d s - WebView est requis par Tachiyomi + WebView est requis pour le fonctionnement l\'application Guide des sources locales %1$s restant @@ -455,7 +453,7 @@ Impossible d\'ouvrir les paramètres de l\'appareil Actualiser les couvertures de la bibliothèque Synchronisation à sens unique pour mettre à jour la progression du chapitre dans les services de suivi. Configurez le suivi des entrées individuelles à partir de leur bouton de suivi. - Cette extension ne fait pas partie de la liste des extensions officielles de Tachiyomi. + Cette extension ne fait pas partie de la liste officielle. Non officiel Vérifier s\'il y a une nouvelle couverture ou synopsis lors des mises à jour de la bibliothèque Par date de téléversement @@ -592,7 +590,7 @@ Format de chapitre invalide Chapitre non trouvé Mode de rotation - Automatique + Auto Mettre à jour les services de suivi lors de la mise à jour de la bibliothèque Actualiser automatiquement les services de suivi Restrictions : %s @@ -605,7 +603,7 @@ Manuel de suivi Désactivé Activé - Rendre les réglages de tri et d\'affichage propres à chaque catégorie + Rendre les réglages de tri propres à chaque catégorie Vous n\'avez pas encore de catégories. Commencer à télécharger Mise à jour de la bibliothèque… (%1$d/%2$d) @@ -662,7 +660,7 @@ Attention : les téléchargements massifs peuvent entraîner un ralentissement des sources ou le blocage de Tachiyomi. Appuyez pour en savoir plus. Tout mettre à jour Mises à jour de l\'application - Effacer le cache du chapitre à la fermeture de l\'application + Vider le cache de chapitre au lancement de l\'application %1$d entrées qui ne sont pas dans la bibliothèque dans la base de données Rien à effacer Échec de la récupération de la liste des extensions @@ -678,7 +676,7 @@ Afficher le titre Grille avec seulement la couverture Panoramique des images larges - Agrandir les images en paysage + Zoom automatique dans les images larges Qui n\'ont pas encore commencé Sauté car la série est terminée Sauté car aucun chapitre n\'est lu @@ -743,7 +741,7 @@ Les %d suivants non lus Les %d suivants non lus - Fonctionne seulement sur les entrées de la bibliothèque et si le chapitre actuel et le suivant sont déjà téléchargés + Fonctionne seulement si le chapitre actuel et le suivant sont déjà téléchargés. Êtes-vous sûr(e) \? Populaire Diviser les grandes images (BETA) @@ -836,11 +834,28 @@ Appuyez deux fois pour zoomer Recherche mensuelle (28 jours) Vérification tardive 10+ - Abandonné \? Fin 20+ et 2 mois + Abandonné \? En retard de 20+ et 2 mois Période de contrôle réussie Prochaine mise à jour prévue Période de diffusion prévue Définir l\'intervalle Valider Intervalle de recherche personnalisé + Appuyez ici pour de l\'aide sur Cloudflare + Débloquer %s + Synchronisation de la bibliothèque + Intervals + Synchronisation de la bibliothèque complété + Licenciés - Aucun chapitres à montrer + Aucune connexion internet + Indice de téléchargement invalidé + Ignoré car aucune sortie n\'était attendue aujourd\'hui + A des résultats + Estimer chaque + HTTP %d, consulter le site Web dans WebView + + 1 jour + %d jours + %d jours + \ No newline at end of file diff --git a/i18n/src/main/res/values-gl/strings.xml b/i18n/src/main/res/values-gl/strings.xml index 78c3b89a4..1b58a9ac9 100644 --- a/i18n/src/main/res/values-gl/strings.xml +++ b/i18n/src/main/res/values-gl/strings.xml @@ -230,8 +230,6 @@ Filtro Menú Axustes - Preme atrás novamente para saír - Desbloquea Tachiyomi Historial Seguimento Capítulos diff --git a/i18n/src/main/res/values-he/strings.xml b/i18n/src/main/res/values-he/strings.xml index 37f3835c0..d419e9157 100644 --- a/i18n/src/main/res/values-he/strings.xml +++ b/i18n/src/main/res/values-he/strings.xml @@ -346,8 +346,6 @@ פריטים בספריה קטגוריות שם - לחץ אחורה שוב כדי לסגור - שחרר את Tachiyomi שום דבר לא נקרא לאחרונה אין עידכונים אחרונים סומן @@ -568,7 +566,7 @@ הושלם ב %1$s עם שגיאה אחת הושלם ב %1$s עם שתי שגיאות הושלם ב %1$s עם %2$s שגיאות - + רשת בוטל/ה @@ -712,7 +710,7 @@ מעקב אחד שני מעקבים %d מעקבים - + ספריה עודכנה לאחרונה ב: %s פצל תמונות מוארכות (בטא) @@ -810,7 +808,7 @@ הפרק הבא שלא נקרא שני הפרקים הבאים שלא נקראו %d הפרקים הבאים שלא נקראו - + מידע דיבוג רישיונות מקורות פתוחים @@ -819,13 +817,13 @@ יום אחד יומיים %d ימים - + חסר פרק אחד חסרים שני פרקים חסרים %1$s פרקים - + הוסף מעקב לחלק מהיצרנים יש הגבלות אפליקציה שהורגות תהליכים ברקע. באתר הזה יש עוד מידע לגבי איך לתקן את זה. diff --git a/i18n/src/main/res/values-hi/strings.xml b/i18n/src/main/res/values-hi/strings.xml index 1d561c2ef..d4cff453b 100644 --- a/i18n/src/main/res/values-hi/strings.xml +++ b/i18n/src/main/res/values-hi/strings.xml @@ -328,7 +328,6 @@ Cloudflare को बायपास करने में विफल बेहतर संगतता के लिए कृपया WebView ऐप को अपडेट करें अध्याय अद्यतन - अनलॉक Tachiyomi सुरक्षित स्क्रीन एप्लिकेशन स्विच करते समय एप्लिकेशन सामग्री छिपाता हैं और स्क्रीनशॉट ब्लॉक करता हैं प्रदर्शन @@ -381,7 +380,6 @@ ताचियोमी के लिए WebView आवश्यक है ओपन सोर्स लाइसेंस वेबसाइट - बाहर निकलने के लिए फिर से वापस दबाएं केवल डाउनलोड किए गए अध्याय %1$s – %2$s बैकअप बहाल करने में विफल रहा diff --git a/i18n/src/main/res/values-hr/strings.xml b/i18n/src/main/res/values-hr/strings.xml index a58cfe039..227cdcc33 100644 --- a/i18n/src/main/res/values-hr/strings.xml +++ b/i18n/src/main/res/values-hr/strings.xml @@ -11,7 +11,7 @@ Ovo proširenje više nije dostupno. Možda neće ispravno funkcionirati i može uzrokovati probleme s aplikacijom. Preporučuje se deinstalacija. Ovo proširenje potpisano je nepovjerljivim certifikatom i nije aktivirano. \n -\nZlonamjerno proširenje može pročitati sve podatke za prijavu koji su spremljeni u programu Tachiyomi ili izvršiti proizvoljni kod. +\nZlonamjerno proširenje može pročitati sve spremljene podatke za prijavu ili izvršiti proizvoljni kod. \n \nVjerujući ovom certifikatu, prihvaćaš te rizike. Nepovjerljivo proširenje @@ -152,8 +152,6 @@ Filtar Izbornik Postavke - Za zatvaranje programa ponovo pritisni natrag - Otključaj Tachiyomi Povijest Praćenje Unosi u biblioteci @@ -398,7 +396,7 @@ Dostupne su %d nove verzije proširenja Dostupno je %d novih verzija proširenja - Za Tachiyomi je potreban WebView + Za funkcioniranje programa je potreban WebView %1$d novo poglavlje %1$d nova poglavlja @@ -426,7 +424,7 @@ Sigurnosna kopija ne sadrži unose u biblioteci. Neispravna datoteka sigurnosne kopije Jednosmjerna sinkronizacija za aktualiziranje napretka poglavlja u usluzi praćenja. Postavi praćenje pojedinačnih unosa manga putem gumba za praćenje. - Ovo proširenje nije sa službenog popisa Tachiyomi proširenja. + Ovo proširenje nije iz službenog popisa. Neslužbeno Provjeri nove naslovnice i pojedinosti prilikom aktualiziranja biblioteke Automatski osvježi metapodatke @@ -831,4 +829,8 @@ Indeks preuzimanja poništen Nije bilo moguće stvoriti datoteku sigurnosne kopije Licencirano – Nema poglavlja za prikaz + Otključaj %s + Ne postoji veza s internetom + HTTP %d, provjeri web stranicu u WebView + Nije bilo moguće povezati se s računalom %s \ No newline at end of file diff --git a/i18n/src/main/res/values-hu/strings.xml b/i18n/src/main/res/values-hu/strings.xml index 0040d89e9..9df1cbc82 100644 --- a/i18n/src/main/res/values-hu/strings.xml +++ b/i18n/src/main/res/values-hu/strings.xml @@ -148,8 +148,6 @@ Összes engedélyezése Kiválasztás megfordítása Menü - A befejezéshez nyomd meg újfent a Vissza gombot - Tachiyomi feloldása A könyvtárad üres Nincs új frissítés Nincs letöltés folyamatban diff --git a/i18n/src/main/res/values-in/strings.xml b/i18n/src/main/res/values-in/strings.xml index e728419c2..1f4824c66 100644 --- a/i18n/src/main/res/values-in/strings.xml +++ b/i18n/src/main/res/values-in/strings.xml @@ -248,11 +248,11 @@ Tidak terpercaya Lepas Ekstensi tidak terpercaya - Ekstensi ini ditanda tangani dengan sertifikat yang tidak terpercaya dan belum diaktifkan. + Ekstensi ini ditandatangani dengan sertifikat tidak tepercaya dan tidak diaktifkan. \n -\nSebuah ekstensi berbahaya dapat membaca kredensial login Anda yang tersimpan pada Tachiyomi atau mengeksekusi kode berbahaya. +\nEkstensi berbahaya dapat membaca kredensial login apa pun yang disimpan atau mengeksekusi kode arbitrer. \n -\nDengan mempercayai sertifikat ini Anda menyetujui resiko tersebut. +\nDengan mempercayai sertifikat ini, Anda menerima risiko ini. Kecepatan animasi ketukan dua kali Tanpa animasi Normal @@ -306,7 +306,6 @@ Ikuti sistem Kelola notifikasi Keamanan dan privasi - Buka Tachiyomi Menu Terbaru Terlama @@ -355,7 +354,7 @@ Sumber Pembaruan ekstensi Membaca - WebView dibutuhkan untuk Tachiyomi + WebView diperlukan agar aplikasi dapat berfungsi Terdapat %d perbaruan ekstensi @@ -374,7 +373,6 @@ Hilangkan tanda Tandai Pilih kebalikan - Tekan lagi untuk keluar Hanya yang sudah diunduh Tersemat Situs web @@ -403,7 +401,7 @@ Selesai dalam %1$s dengan %2$s kesalahan Sinkronisasi satu arah untuk memperbarui kemajuan bab dalam layanan pelacakan. Siapkan pelacakan untuk entri individu dari tombol pelacakan mereka. - Ekstensi ini bukan dari daftar ekstensi resmi Tachiyomi. + Ekstensi ini bukan dari daftar resmi. Tidak resmi Periksa sampul dan detail baru saat memperbarui pustaka Segarkan metadata secara otomatis @@ -799,4 +797,8 @@ Pelacak login Tidak dapat membuat file cadangan Lisensi - Tidak ada chapter untuk ditampilkan + Buka kunci %s + Tidak ada koneksi Internet + HTTP %d, periksa situs web di WebView + Tidak dapat mencapai %s \ No newline at end of file diff --git a/i18n/src/main/res/values-it/strings.xml b/i18n/src/main/res/values-it/strings.xml index ace83b64e..76403f394 100644 --- a/i18n/src/main/res/values-it/strings.xml +++ b/i18n/src/main/res/values-it/strings.xml @@ -278,7 +278,7 @@ Estensione non attendibile Questa estensione è stata firmata con un certificato non attendibile e non è stata attivata. \n -\nUn\'estensione maliziosa potrebbe leggere credenziali di accesso all\'interno di Tachiyomi, o eseguire codice dannoso. +\nUn\'estensione maliziosa potrebbe leggere credenziali di accesso salvate o eseguire codice dannoso. \n \nFidandoti di questo certificato accetti questi rischi. Velocità animazioni doppio tocco @@ -362,7 +362,6 @@ Impossibile bypassare Cloudflare Per favore aggiorna l\'app WebView per una migliore compatibilità Aggiornamenti capitoli - Sblocca Tachiyomi Schermo sicuro nasconde i contenuti dell\'app quando cambi applicazione e blocca gli screenshot Visualizzazione Aggiornamenti estensione @@ -424,9 +423,8 @@ Ripristino già in corso Backup fallito Il backup è già in corso - Premi indietro nuovamente per uscire Solo scaricati - È necessaria l\'app WebView per Tachiyomi + WebView è necessaria per il funzionamento dell\'app Modalità di lettura Per questa serie Guida alle fonti locali @@ -461,7 +459,7 @@ Fonti mancanti: Il backup non contiene alcuna voce di libreria. File di backup invalido - Questa estensione non è presente nella lista ufficiale delle estensioni di Tachiyomi. + Questa estensione non è dalla lista ufficiale. Non ufficiale Controlla nuove copertine e descrizioni durante l\'aggiornamento della libreria Ricarica metadati automaticamente @@ -867,4 +865,5 @@ HTTP %d, controlla il sito nella WebView Nessuna connessione ad internet %s non raggiungibile + Sblocca %s \ No newline at end of file diff --git a/i18n/src/main/res/values-ja/strings.xml b/i18n/src/main/res/values-ja/strings.xml index c4b2d407b..6041abf98 100644 --- a/i18n/src/main/res/values-ja/strings.xml +++ b/i18n/src/main/res/values-ja/strings.xml @@ -165,7 +165,7 @@ 同期 この拡張機能は信頼できない証明書でサインされているため、有効にされていません。 \n -\n悪意のある拡張機能はTachiyomiに保存されているすべてのログイン情報を読み取ることや、任意コード実行をすることができます。 +\n悪意のある拡張機能は保存されているすべてのログイン情報を読み取ることや、任意コード実行をすることができます。 \n \nこれらのリスクを受け入れ、この証明書を信頼しますか? ページ数を表示 @@ -317,7 +317,6 @@ %1$s分後 セキュア画面 - Tachiyomiのロックを解除する %1$d新しい章 @@ -365,7 +364,7 @@ 乗算 バンディングを軽減しますが、パフォーマンスを影響するかもしれません 画面の切り抜きエリアにも内容を表示 - この拡張機能はTachiyomiの公式拡張機能リストに含まれていません。 + この拡張機能は公式リストに含まれていません。 非公式 更新あり @@ -389,10 +388,9 @@ 全て有効にする 選択を反転 メニュー - もう一度押して終了します 章の更新 WebViewアプリを更新して互換性を向上させてください - TachiyomiはWebViewを必要としています + WebViewが必要です %d件の拡張機能の更新が利用可能 @@ -802,4 +800,5 @@ HTTP %d、WebViewでこのWebサイトを確認してください インターネット接続がありません %sにアクセスできませんでした + %sをアンロック \ No newline at end of file diff --git a/i18n/src/main/res/values-jv/strings.xml b/i18n/src/main/res/values-jv/strings.xml index 623dfc00c..14b9636aa 100644 --- a/i18n/src/main/res/values-jv/strings.xml +++ b/i18n/src/main/res/values-jv/strings.xml @@ -81,7 +81,6 @@ Durung kewoco Saringan Pengaturan - Mbukak Tachiyomi Sejarah Kategori Ora ono updetan anyar @@ -120,7 +119,6 @@ Kelacak Diwenehi tandha Menu - Pencet bali maneh kanggo metu Ngelacak Bab Sampeyan ora duwe kategori. Dhemok tombol tambah kanggo nggawe siji kategori kanggo ngatur perpustakaane sampeyan. diff --git a/i18n/src/main/res/values-ka-rGE/strings.xml b/i18n/src/main/res/values-ka-rGE/strings.xml index 6ff46b3d7..11a537fe1 100644 --- a/i18n/src/main/res/values-ka-rGE/strings.xml +++ b/i18n/src/main/res/values-ka-rGE/strings.xml @@ -346,8 +346,6 @@ რეზერვი გავრცობები გავრცობის შესახებ - Tachiyomi-ს განბლოკვა - გასასვლელად დააჭირეთ ისევ უკან გლობალური ძებნა კატეგორიების მინიჭება ყდის რედაქტირება diff --git a/i18n/src/main/res/values-kk/strings.xml b/i18n/src/main/res/values-kk/strings.xml index 7cf3f4dca..58d841434 100644 --- a/i18n/src/main/res/values-kk/strings.xml +++ b/i18n/src/main/res/values-kk/strings.xml @@ -16,9 +16,7 @@ Көшу Әдепкі Ескерту - Tachiyomi-ді бұғаттан босату Өзгертуді растау үшін аутентификация өтіңіз - Шығу үшін қайтадан басыңыз Мәзір Сүзгі Бетбелгіленген diff --git a/i18n/src/main/res/values-km/strings.xml b/i18n/src/main/res/values-km/strings.xml index 5c3f7e44a..85cbee0ce 100644 --- a/i18n/src/main/res/values-km/strings.xml +++ b/i18n/src/main/res/values-km/strings.xml @@ -22,7 +22,6 @@ ប្រភពម៊េងហ្គា ជំនួយ លំនាំដើម - បើកតាឈិយ៉ូមិ ហ្វីលធឺ បានបញ្ចូលទៅក្នុងបណ្ណាល័យ បានដាក់ការតាមដានការអាន @@ -76,7 +75,6 @@ អ្នកពុំមានការទម្រៀបម៊េងហ្គាឡើយ។ ចុចប៊ូតុងសញ្ញាបូកដើម្បីទម្រៀបម៊េងហ្គាសម្រាប់បណ្ណាល័យរបស់អ្នក។ ម៊េងហ្គា Authenticateដើម្បីបញ្ចាក់ពីការកែប្រែ - ចុចថយម្ដងទៀតដើម្បីចេញ ការកំណត់ កន្លែងកំណត់ បញ្ចាក់ភាគមុនថាបានអាន diff --git a/i18n/src/main/res/values-kn/strings.xml b/i18n/src/main/res/values-kn/strings.xml index 5257f612a..ed01f878f 100644 --- a/i18n/src/main/res/values-kn/strings.xml +++ b/i18n/src/main/res/values-kn/strings.xml @@ -93,8 +93,6 @@ ಸೋಸು ಸಲಹಾಕಾರ ಸಂಯೋಜನೆಗಳು - ನಿರ್ಗಮಿಸಲು ಮತ್ತೊಮ್ಮೆ ಒತ್ತಿರಿ - ತಚಿಯೋಮಿಯನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ ಇತಿಹಾಸ ಟ್ರ್ಯಾಕಿಂಗ್ ಅಧ್ಯಾಯಗಳು diff --git a/i18n/src/main/res/values-ko/strings.xml b/i18n/src/main/res/values-ko/strings.xml index f4996d9c3..f6c3e5560 100644 --- a/i18n/src/main/res/values-ko/strings.xml +++ b/i18n/src/main/res/values-ko/strings.xml @@ -292,8 +292,6 @@ 도움말 이메일 주소 웹사이트 - Tachiyomi 잠금 해제 - 뒤로 가기를 한 번 더 누르면 앱을 종료합니다 메뉴 더 보기 소스 diff --git a/i18n/src/main/res/values-lt/strings.xml b/i18n/src/main/res/values-lt/strings.xml index 97333bc2d..820fc3087 100644 --- a/i18n/src/main/res/values-lt/strings.xml +++ b/i18n/src/main/res/values-lt/strings.xml @@ -3,8 +3,6 @@ Filtras Meniu Nustatymai - Paspauskite atgal, kad išeitumėte - Atrakinkite Tachiyomi Istorija Sekimas Skyriai diff --git a/i18n/src/main/res/values-lv/strings.xml b/i18n/src/main/res/values-lv/strings.xml index 8ada4db03..899565ddf 100644 --- a/i18n/src/main/res/values-lv/strings.xml +++ b/i18n/src/main/res/values-lv/strings.xml @@ -71,7 +71,7 @@ Kļūda Lejupielādētājs Lai uzlabotu saderību, lūdzu, atjauniniet WebView lietotni - Tachiyomi ir nepieciešams WebView + Lai aplikācija strādātu ir nepieciešams WebView Dublējuma atjaunošana neizdevās Dublējuma atjaunošana Atjaunošana jau notiek @@ -90,7 +90,6 @@ Dublējumā nav neviena bibliotēkas ieraksta. Paplašinājumu informācija Paplašinājumi - Atslēgt Tachijomi Abi Vertikāls Horizontāls @@ -116,7 +115,6 @@ Pievienošanas datums Jaunākā nodaļa Izvēlne - Vēlreiz nospiediet atpakaļ, lai izietu Jums nav nevienas kategorijas. Pieskarieties plus pogai, lai izveidotu kategoriju savas bibliotēkas organizēšanai. Jūsu bibliotēka ir tukša Nekas nesen lasīts @@ -131,7 +129,7 @@ Lejuplādēt Ainava Portrets - Vienumi rindā + Režģa izmērs Displejs Slēpt paziņojumu saturu Drošs ekrāns paslēpj saturu mainot lietotnes, un bloķē ekrānuzņēmumus @@ -247,7 +245,7 @@ Neuzticams paplašinājums Šis paplašinājums tika parakstīts ar neuzticamu sertifikātu, un tas netika aktivizēts. \n -\nĻaunprātīgs paplašinājums var nolasīt visus pieteikšanās akreditācijas datus, kas saglabāti Tachiyomi, vai izpildīt patvaļīgu kodu. +\nĻaunprātīgs paplašinājums var nolasīt visus saglabātos pieteikšanās akreditācijas datus vai izpildīt patvaļīgu kodu. \n \nUzticoties šim sertifikātam, jūs piekrītat šiem riskiem. Mantots @@ -283,7 +281,7 @@ Ar nelasītu(ām) nodaļu(ām) Kas nav sāktas Vienmēr jautāt - Kategorijas iestatījumi kārtošanai un rādīšanai + Kategorijas iestatījumi kārtošanai Izslēgto kategoriju ieraksti netiks atjaunināti, pat ja tie ir iekļautajās kategorijās. Neviens Iekļaut: %s @@ -294,7 +292,7 @@ Neoficiāls Neuzticams Šis paplašinājums vairs nav pieejams. Tas var nedarboties pareizi un var radīt problēmas ar lietotni. Ieteicams to atinstalēt. - Šis paplašinājums nav no oficiālo Tachiyomi paplašinājumu saraksta. + Šis paplašinājums nav no oficiālā saraksta. Sadalīt platas lapas Apvērst dalītās lapas izvietojumu Rādīt saturu izgriezuma apgabalā @@ -307,7 +305,7 @@ Ik pēc 2 dienam Ik pēc 3 dienām Tikai uz Wi-Fi - Automātisks + Auto Turēt ekrānu ieslēgtu Centrs Rotācijas tips @@ -340,7 +338,7 @@ Pelēks Atspējots Balts - Nepārtraukta vertikāle + Garā strīpā ar pārtraukumu Sānu platums Izslēgtās kategorijas Lokālais avots @@ -352,8 +350,8 @@ Mala Pa labi un pa kreisi Pa labi - No kreisās puses uz labo - Webtoon + Lapaspuses (no kreisās puses uz labo) + Garā strīpā Skāriena zonas Izstiept Ietilpt platumā @@ -363,8 +361,8 @@ Portrets Aizslēgts portreta režīmā Lasīšanas režīms - No labās puses uz kreiso - Vertikāls + Lapaspuses (no labās puses uz kreiso) + Lapaspuses (vertikāli) Bibliotēkas ieraksti Ātrs Noklusējuma rotācijas tips @@ -379,7 +377,7 @@ Izlaist filtrētās nodaļas Navigācija Invertēt skaļuma regulēšanas taustiņus - Rādīt ar ilgu pieskārienu + Rādīt darbīūbas ar ilgu pieskārienu Izveido mapes atbilstoši ieraksta nosaukumam Fona krāsa Mēroga tips @@ -408,7 +406,7 @@ Drukāt verbose žurnālus sistēmas žurnālā (samazina programmas veiktspēju) Atjaunot progresu pēc lasīšanas Izsekošanas rokasgrāmata - Saglabā avārijas žurnālu + Dalīties ar avārijas žurnālu Saglabā kļūdu žurnālus failā priekš koplietošanas ar izstrādātājiem Notīrīt nodaļas kešatmiņu Atsvaidzināt bibliotēkas vākus @@ -416,7 +414,7 @@ Nav bibliotēkas ierakstu, ko dublēt Atjaunošana atcelta Dublēšana/atjaunošana var nedarboties pareizi, ja ir atspējota MIUI Optimization. - Notīriet nodaļu kešatmiņu, aizverot lietotni + Notīriet nodaļu kešatmiņu, atverot lietotni %1$d ierakstu, kas nav bibliotēkas, ir datu bāzē Tīkls Dati @@ -630,9 +628,9 @@ Lietotnes atjauninājumi Ir pieejama jauna versija! Atjaunināti noklusējuma nodaļu iestatījumi - Palielināt ainavas attēlu + Automātiski tuvināt ainavas attēlus Nākošā lapa - Pieskaroties izplest platus attēlus + Izplest platus attēlus Nevar atvērt pēdējo lasīto nodaļu Pārlasīšana Vai dzēst lejupielādētās nodaļas\? @@ -701,7 +699,7 @@ Paisuma vilnis Vairāku Lejupielādēt uz priekšu - Darbojas tikai ar ierakstiem bibliotēkā un tad, ja pašreizējā un nākamā nodaļa jau ir lejupielādēta + Darbojas tikai ja pašreizējā nodaļa + nākošā nodaļa ir jau lejupielādēta. Jūsu bibliotēkā ir ieraksts ar tādu pašu nosaukumu. \n \nVai joprojām vēlaties turpināt\? @@ -743,7 +741,7 @@ Vienvirziena progresa sinhronizācija, uzlabota sinhronizācija Avoti, paplašinājumi, globālā meklēšana Tēma, datuma un laika formāti - Kategorijas, globāli atjauninājumi + Kategorijas, globāli atjauninājumi, nodaļu vilkšana Rādīt nelasīto skaitu uz atjauninājumu ikonas Logrīks nav pieejams, ja ir iespējota lietotņu bloķēšana RARv5 formāts netiek atbalstīts @@ -762,7 +760,7 @@ %1$s kļūda: %2$s Atjauninājums jau darbojas - %s radās neparedzēta kļūda. Mēs iesakām izveidot šo ziņojumu ekrānuzņēmumu, atrast avārijas žurnālu un pēc tam kopīgot to mūsu atbalsta kanālā Discord lietotnē. + %s radās neparedzēta kļūda. Mēs iesakām dalīties ar avārijas žurnālu mūsu atbalsta kanālā Discord lietotnē. Pagrieziet platas lapas, lai tās ietilptu Apvērst orientācija pagrieztām platām lapām Sadalīt augstus attēlus @@ -794,4 +792,45 @@ Globālajā atjauninājumā Kopā *obligāti + Nevarēja izveidot dublējuma failu + Lejupielādes indeks ir nederīgs + Licencēts - Nav nevienu nodaļu ko parādīt + Izlaists, jo šodien nebija gaidīta jauna nodaļa + Vilkt uz labās puses darbību + Atkļūdošanas informācija + Pieskarieties šeit, lai iegūtu palīdzību ar Cloudflare + Ir rezultāti + Noņemt arī no %s + Vilkt uz kreisās puses darbību + Novērtēt katru + Iestatīt intervālu + Pielāgots datu iegūšanas intervāls + Iegūt katru mēnesi (28 dienas) + Nokārtots pārbaudes periods + Nākamais gaidāmais atjauninājums + Pieteikšanās izsekošana + Sinhronizē bibliotēku + Bibliotēkas sinhronizācija ir pabeigta + Intervāli + + %d dienas + %d diena + %d dienas + + Šis noņems locālo izsekošanu. + Izdzēst lejupielādētos + Vai noņemt %s izsekošanu\? + OK + Ārpus paredzamā izlaišanas perioda + Dubult-pieskarieties, lai tuvinātu + %d katrā rindā + Atbloķēt %s + Par vēlu +10 pārbaudes + Pametāt\? Par vēlu +20 un 2 mēnešus + Vilkt nodaļas + Atjaunināt katru + Pielāgot intervālu + HTTP %d, pārbaudiet vietni iekš WebView + Nav interneta savienojuma + Nevarēja sasniegt %s \ No newline at end of file diff --git a/i18n/src/main/res/values-mr/strings.xml b/i18n/src/main/res/values-mr/strings.xml index a5974e747..9ae0f9de6 100644 --- a/i18n/src/main/res/values-mr/strings.xml +++ b/i18n/src/main/res/values-mr/strings.xml @@ -27,8 +27,6 @@ सामान्य मेनू बुकमार्क आहे - अॅप बंद करण्यासाठी बॅक पुन्हा दाबा - तचीयोमी उघडा ट्रॅकिंग लायब्ररी इंत्रिज श्रेण्या diff --git a/i18n/src/main/res/values-ms/strings.xml b/i18n/src/main/res/values-ms/strings.xml index 3814b4f28..45fda159a 100644 --- a/i18n/src/main/res/values-ms/strings.xml +++ b/i18n/src/main/res/values-ms/strings.xml @@ -252,7 +252,7 @@ Sambungan tak dipercayai Sambungan ini telah ditandatangani dengan sijil tidak dipercayai dan ia tidak diaktifkan. \n -\nSambungan yang berniat jahat kemungkinan membaca sebarang kelayakan log masuk yang di simpan dalam Tachiyomi atau melaksanakan kod sesuka hati. +\nSambungan yang berniat jahat kemungkinan membaca sebarang kelayakan log masuk yang di simpan atau melaksanakan kod sesuka hati. \n \nDengan mempercayai sijil ini, anda menerima risiko tersebut. Kelajuan animasi ketik dua kali @@ -327,7 +327,6 @@ Gagal untuk memintas Cloudflare Sila kemas kini aplikasi WebView untuk keserasian yang lebih baik Pengemaskinian bab - Buka kunci Tachiyomi Skrin keselamatan menyembunyikan kandungan aplikasi apabila menukar aplikasi dan sekat tangkapan skrin Paparan @@ -365,7 +364,7 @@ Pilih songsang Sumber Tambahan sisi - WebView diperlukan untuk Tachiyomi + WebView diperlukan untuk aplikasi berfungsi Bab %1$s - %2$s Tambah penjejakan Tutup @@ -382,7 +381,6 @@ Sandaran sedang dijalankan Buang sematkan Sematkan - Tekan kembali sekali lagi untuk keluar Dimuat turun sahaja Terakhir digunakan Semak untuk kemas kini @@ -410,7 +408,7 @@ Tiada sumber: Sandaran tidak mengandungi apa-apa entri pustaka. Fail sandaran tidak sah - Sambungan ini bukan daripada senarai sambungan Tachiyomi yang rasmi. + Sambungan ini bukan daripada senarai yang rasmi. Tidak rasmi Semak muka hadapan dan tentang baharu bila mengemaskini pustaka Segar semula metadata secara automatik @@ -802,4 +800,5 @@ Indeks muat turun tidak sah Ketik di sini untuk bantuan berkenaan Cloudflare HTTP %d, semak laman web dalam WebView + Buka kunci %s \ No newline at end of file diff --git a/i18n/src/main/res/values-nb-rNO/strings.xml b/i18n/src/main/res/values-nb-rNO/strings.xml index f96af916c..ce9561b16 100644 --- a/i18n/src/main/res/values-nb-rNO/strings.xml +++ b/i18n/src/main/res/values-nb-rNO/strings.xml @@ -323,7 +323,6 @@ Sikker skjerm Kapitteloppdateringer - Lås opp Tachiyomi Kapittel %1$s E-postadresse I biblioteket @@ -351,7 +350,6 @@ Hopp over filtrerte kapitler Skjul merknadsinnhold Sikker skjerm skjuler programinnhold ved bytting av programmer og blokker skjermavbildninger - Trykk \"Tilbake\" igjen for å avslutte Kun nedlastet Uoffisiell Lesemodus diff --git a/i18n/src/main/res/values-ne/strings.xml b/i18n/src/main/res/values-ne/strings.xml index 6bf9af325..edec1498a 100644 --- a/i18n/src/main/res/values-ne/strings.xml +++ b/i18n/src/main/res/values-ne/strings.xml @@ -94,8 +94,6 @@ हालै केहि पढेको छैन हालैका कुनै अपडेट छैन डाउनलोड लाम - बाहिर निस्किन फेरि फिर्ता थिच्नुहोस् - ताचियोमी अनलक गर्नुहोस् कुनै डाउनलोडहरू छैन मद्दत एक्सटेन्शनको जानकारी diff --git a/i18n/src/main/res/values-nl/strings.xml b/i18n/src/main/res/values-nl/strings.xml index 957d93c98..06ea1cc29 100644 --- a/i18n/src/main/res/values-nl/strings.xml +++ b/i18n/src/main/res/values-nl/strings.xml @@ -327,7 +327,6 @@ Kon Cloudflare niet omzeilen Gelieve de WebView-app bij te werken voor betere compatibiliteit Hoofdstukupdates - Ontgrendel Tachiyomi Veilig scherm modus verbergt de inhoud van de app bij het wisselen en blokkeert schermafbeeldingen Weergave Verplaats naar beneden @@ -337,7 +336,6 @@ Vastpinnen Bronnen Selectie omkeren - Druk nogmaals op terug om te verlaten Herstellen geannuleerd Herstellen mislukt Er wordt al een back-up hersteld @@ -745,4 +743,78 @@ Dit gaat je eerder geselcteerde startdatum %s verwijderen Download verwijderen Overgeslagen omdat serie geen updates vereist. + %s is een onverwachte fout tegengekomen. We raden u aan de crashlogboeken te delen in ons ondersteuningskanaal op Discord. + Foutopsporingsinformatie + Voltooide titels + Buiten verwachte vrijgave periode + Interval instellen + Aangepast ophaalinterval + Maandelijks ophalen (28 dagen) + Controleperiode overschreden + Volgende verwachte update + Splits hoge afbeeldingen + Gelicenseerd - Geen hoofdstukken te laten zien + Draairichting van geroteerde brede pagina\'s omdraaien + Dubbeltik om te zoomen + Log-in volgen + Bibliotheek synchroniseren + Heeft resultaten + Dit zal jouw eerder geselecteerde einddatum weg halen van %s + Dit zal de tracking lokaal verwijderen. + Haal ook weg van %s + Overlay + Overzicht + Leesduur + Schat elke + Herstart de applicatie + Interval aanpassen + Download Index geïnvalideerd + + + + + Maak de downloadindex ongeldig + + + + + OK + Swipe naar de linker actie + Intervallen + Haal %s tracking weg\? + Ontgrendel %s + Swipe naar de juiste actie + %d per rij + Hoofdstuk veeg + Roteer brede pagina\'s zodat ze passen + Kon een backup-bestand niet creëren + Bibliotheeksynchronisatie beëindigd + Trackers + Overgeslagen omdat geen uitgave is verwacht vandaag + *vereist + Totaal + Late 10+ controle + Gevallen\? Late 20+ en 2 maanden + Lees + Gevolgde titels + Gemiddelde score + %du + U staat op het punt om \"%s\" te verwijderen uit uw bibliotheek + %ds + Kon bestandspad van pagina %d niet vinden + Titels + Open op GitHub + Geen titels gevonden in deze categorie + Geen internet verbinding + Kon niet %s bereiken + Gebruikt + N.v.t + Stel in om te updaten iedere + Tik hier voor hulp met Cloudflare + %dd + Category is leeg + %dm + Er is een nieuwe versie beschikbaar van de officiële uitgavens. Tik om te leren hoe u kunt migreren vanuit niet-officiële F-Droid-releases. + HTTP %d, check website in WebView + In globale update \ No newline at end of file diff --git a/i18n/src/main/res/values-nn/strings.xml b/i18n/src/main/res/values-nn/strings.xml index 41326b8e1..ece30340f 100644 --- a/i18n/src/main/res/values-nn/strings.xml +++ b/i18n/src/main/res/values-nn/strings.xml @@ -12,7 +12,6 @@ Historikk Standard Åtvaring - Lås opp Tachiyomi Autentiser for å stadfesta endring Filter Bokmerket @@ -87,7 +86,6 @@ Ingen nylege oppdateringar Bibliotek Kjelder - Trykk tilbake igjen for å avslutta Innstillingar Meny Sett kategoriar diff --git a/i18n/src/main/res/values-pl/strings.xml b/i18n/src/main/res/values-pl/strings.xml index 66497759a..e208a925c 100644 --- a/i18n/src/main/res/values-pl/strings.xml +++ b/i18n/src/main/res/values-pl/strings.xml @@ -8,7 +8,7 @@ Kolejka pobierania Historia Ustawienia - Filtrowanie + Filtry Nieprzeczytane Szukaj Zaznacz wszystko @@ -16,7 +16,7 @@ Aktualizacje Kopia zapasowa i przywracanie Zakładki - Usuń filtrowanie + Usuń filtr Ostatnio czytane Oznacz jako przeczytane Oznacz jako nieprzeczytane @@ -138,7 +138,7 @@ Od lewej do prawej Od prawej do lewej Pionowy - Web-komiks + Długi pasek Domyślny styl czytania Dopasuj do ekranu Rozciągnij @@ -261,7 +261,7 @@ Niezaufane rozszerzenie To rozszerzenie było podpisane niezaufanym certyfikatem i nie zostało aktywowane. \n -\nZłośliwe rozszerzenie może odczytać dane logowania przechowywane w Tachiyomi albo uruchomić złośliwy kod. +\nZłośliwe rozszerzenie może odczytać dane logowania albo uruchomić złośliwy kod. \n \nUfając temu rozszerzeniu akceptujesz to zagrożenie. Zaznacz dane do zawarcia @@ -282,7 +282,7 @@ Otwórz używając WebView Kolor 32-bitowy Pomiń rozdziały ozn. jako przeczytane - Pokaż po przytrzymaniu + Pokaż akcje po przytrzymaniu Tryb mieszania kolorów Nakładka Pomnożenie @@ -338,7 +338,6 @@ Odwróć zaznaczenie Ostatni rozdział Menu - Odblokuj Tachiyomi Źródła Rozdział %1$s Aktualizowanie biblioteki @@ -371,7 +370,6 @@ Ukryj ekran Odepnij Przypnij - Wciśnij wstecz ponownie, aby wyjść Więcej Rozdz. %1$s - %2$s W bibliotece @@ -379,7 +377,7 @@ Ostatnio używane Przesyłanie postępu czytania do zewnętrznego serwisu. Ustaw śledzenie guzikiem \"Śledzenie\" w wybranych tytułach. Aktualizacje rozszerzeń - WebView jest wymagany do poprawnego działania Tachiyomi + WebView jest wymagany do poprawnego działania aplikacji Dostępna aktualizacja rozszerzenia Dostępne %d aktualizacje rozszerzeń @@ -429,7 +427,7 @@ Wykonano w %1$s z %2$s błędami Czytane - Te rozszerzenie nie jest na liście oficjalnych rozszerzeń Tachiyomi. + Te rozszerzenie nie jest na liście oficjalnych rozszerzeń. Nieoficjalne Po dacie dodania Dane @@ -561,7 +559,7 @@ Źródło nie jest wspierane Nieprzeczytane Orientacja ekranu - Automatyczne + Automatycznie Utwórz foldery względem tytułu Zapisz strony do osobnych folderów Akcje @@ -654,7 +652,7 @@ Posiada nieprzeczytane rozdziały FAQ i poradniki Brak przeczytanych rozdziałów - Przybliżaj poziome obrazy + Automatycznie przybliżaj poziome obrazy Pokaż Przesuń szeroki obraz Siatka z samych okładek @@ -825,4 +823,20 @@ %d dni Synchronizowanie biblioteki + Nie można wykonać kopi zapasowej + Interwały + Usuń też z %s + HTTP %d, otwórz w WebView + Brak połączenia z internetem + Nie można połączyć się z %s + Przestań śledzić %s\? + Usuń pobrane + Synchronizacja biblioteki zakończona + Indeksy pobrań unieważnione + Naciśnij tutaj aby uzyskać pomoc dotyczącą Cloudflare + Odblokuj %s + Dostosowany interwał aktualizacji + W miesiącu (28 dni) + OK + To usunie śledzenie lokalne. \ No newline at end of file diff --git a/i18n/src/main/res/values-pt-rBR/strings.xml b/i18n/src/main/res/values-pt-rBR/strings.xml index 5e6962fb1..3b7f69478 100644 --- a/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/i18n/src/main/res/values-pt-rBR/strings.xml @@ -252,7 +252,7 @@ Extensão não confiável Esta extensão foi assinada com um certificado não confiável e não foi ativada. \n -\nUma extensão maliciosa poderia ler quaisquer credenciais de login armazenadas no Tachiyomi ou executar códigos arbitrários. +\nUma extensão maliciosa poderia ler quaisquer credenciais de login armazenadas ou executar códigos arbitrários. \n \nAo confiar neste certificado, você estará aceitando estes riscos. Velocidade da animação do toque duplo @@ -329,7 +329,6 @@ Falha ao contornar o Cloudflare Por favor, atualize o aplicativo de WebView para uma melhor compatibilidade Atualizações de capítulos - Desbloquear o Tachiyomi A tela segura oculta os conteúdos do aplicativo durante a troca de aplicativos e impede capturas de tela Visualização @@ -360,7 +359,7 @@ Menu Mais novos Mais antigos - Mover para o topo + Mover para o começo Mover para o final Atualização de extensão disponível @@ -383,8 +382,7 @@ Na biblioteca Menos Mais - Pressione voltar novamente para sair - A WebView é necessária para o Tachiyomi + A WebView é necessária para o funcionamento do app Licenças de código aberto Site Somente disponíveis offline @@ -421,7 +419,7 @@ Sincronização unidirecional para atualizar o progresso dos capítulos nos serviços de monitoramento. Configure o monitoramento para itens individuais a partir de seus botões de monitoramento. Atualizar as capas da biblioteca - Esta extensão não é da lista oficial de extensões do Tachiyomi. + Esta extensão não é da lista oficial. Não oficial Pela data de envio Dados @@ -654,7 +652,7 @@ %1$d atualização(ões) falhou(aram) Toque para saber mais Retrato invertido - Mover série para o topo + Mover série para o começo Desativado Uma nova versão está disponível nos releases oficiais. Toque para saber como migrar dos releases não oficiais do F-Droid. Erro ao salvar a imagem @@ -834,4 +832,6 @@ HTTP %d, verifique o site na WebView Sem conexão de internet Não foi possível resolver %s + Desbloquear o %s + Mover série para o final \ No newline at end of file diff --git a/i18n/src/main/res/values-pt/strings.xml b/i18n/src/main/res/values-pt/strings.xml index b216c53ae..f0a0dd8e5 100644 --- a/i18n/src/main/res/values-pt/strings.xml +++ b/i18n/src/main/res/values-pt/strings.xml @@ -359,7 +359,6 @@ Falha ao contornar o Cloudflare Por favor, atualize a app de WebView para melhor compatibilidade Atualizações de capítulos - Desbloquear o Tachiyomi Ecrã seguro esconde os conteúdos da app durante a troca de apps e impedir capturas de ecrã Visualização Capítulo %1$s e %2$d mais @@ -414,7 +413,6 @@ Restauro já em progresso Cópia de segurança falhou Cópia de segurança já em progresso - Pressione novamente para sair Apenas transferidos WebView é necessária para Tachiyomi Cap. %1$s - %2$s diff --git a/i18n/src/main/res/values-ro/strings.xml b/i18n/src/main/res/values-ro/strings.xml index 58d614805..1fa29539a 100644 --- a/i18n/src/main/res/values-ro/strings.xml +++ b/i18n/src/main/res/values-ro/strings.xml @@ -314,7 +314,6 @@ Gestionați notificările Securitate Necesită deblocare - Deblochează Tachiyomi Ultimul capitol Blocați când este inactiv Întotdeauna @@ -389,7 +388,6 @@ Pagină web Restaurarea copiei de rezervă a eșuat Crearea copiei de rezervă a eșuat - Apăsați din nou pentru a ieși Doar descărcate Restaurare anulată Restaurarea este deja în curs de desfășurare diff --git a/i18n/src/main/res/values-ru/strings.xml b/i18n/src/main/res/values-ru/strings.xml index 76a5424f0..e8c850ca3 100644 --- a/i18n/src/main/res/values-ru/strings.xml +++ b/i18n/src/main/res/values-ru/strings.xml @@ -251,7 +251,7 @@ Ненадёжное расширение Это расширение было подписано ненадёжным сертификатом и не было активировано. \n -\nВредоносное расширение может считывать любые учетные данные для входа, хранящиеся в Tachiyomi, или выполнять произвольный код. +\nВредоносное расширение может считывать и хранить любые учётные данные для входа или выполнять произвольный код. \n \nДоверяя этому сертификату, вы принимаете эти риски. Скорость анимации при двойном нажатии @@ -372,7 +372,6 @@ В начало В конец Обновления расширений - Разблокировать Tachiyomi Меню Источники Чтение @@ -384,9 +383,8 @@ Открепить Закрепить Добавить отслеживание - Нажмите ещё раз, чтобы выйти Только загруженные главы - Для Tachiyomi необходим WebView + Для работы приложения необходимо WebView Меньше Больше В библиотеке @@ -429,7 +427,7 @@ Выполнено за %1$s с %2$s ошибками Односторонняя синхронизация для обновления прогресса в сервисах отслеживания. Настройте отслеживание при помощи кнопки «Отслеживание». - Это расширение не входит в официальный список расширений Tachiyomi. + Это расширение не входит в официальный список расширений. Неофициальное Дата добавления Данные @@ -823,7 +821,7 @@ Настроить интервал Задать интервал Проверка поздних 10+ дней - Прошедшая проверка периода + Срок проверки истёк Следующее ожидамое обновление За пределами ожидаемого периода выпуска Задать обновления каждые @@ -835,7 +833,7 @@ Пропущено, т.к сегодня не ожидается выпуска Удалить отслеживание %s\? - Это удалит отслеживание локально. + Это удалит отслеживание в приложении. Также удалить из %s ОК Удалить загруженное @@ -845,9 +843,10 @@ Нажмите здесь, чтобы получить помощь с Cloudflare Индекс загрузок недействителен Не удалось создать файл резервной копии - Лицензировано - Нет глав для показа + Лицензировано - Нет глав Вход в сервис отслеживания - HTTP %d, проверить сайт в WebView + HTTP %d, проверьте сайт в WebView Нет подключения к интернету Не удалось достичь %s + Разблокировать %s \ No newline at end of file diff --git a/i18n/src/main/res/values-sa/strings.xml b/i18n/src/main/res/values-sa/strings.xml index 73aa8d2f1..25834e3e2 100644 --- a/i18n/src/main/res/values-sa/strings.xml +++ b/i18n/src/main/res/values-sa/strings.xml @@ -17,12 +17,10 @@ चरित्रम् मूलानि प्राथमिकम् - ताचियोमिम् उद्घाटयतु ग्रन्थालयः प्रतिलेखनं प्रतिसंस्कारं च पूर्वसूचना परिवर्तनं दृढीकर्तुं प्रमाणीकरोतु - निष्क्रमितुं पृष्ठगण्डं पुनः नोदयतु सूचिः शोधकम् पुटचिह्नं कृतानि diff --git a/i18n/src/main/res/values-sah/strings.xml b/i18n/src/main/res/values-sah/strings.xml index 3bf1ae52f..486d9d40e 100644 --- a/i18n/src/main/res/values-sah/strings.xml +++ b/i18n/src/main/res/values-sah/strings.xml @@ -27,8 +27,6 @@ Биилтирэ Талба Түстэл - Өссө биирдэ төттөрүнү баттаан, тахсар курдук - Тachiyomi арыйыыта История Кэтээһин Түһүмэхтэр diff --git a/i18n/src/main/res/values-sc/strings.xml b/i18n/src/main/res/values-sc/strings.xml index eb9749529..8d4b42c45 100644 --- a/i18n/src/main/res/values-sc/strings.xml +++ b/i18n/src/main/res/values-sc/strings.xml @@ -328,7 +328,6 @@ Isfrancamentu de Cloudflare fallidu Agiorna s\'aplicatzione de WebView pro otènnere una cumpatibilidade prus manna Agiornamentos de sos capìtulos - Isbloca Tachiyomi S\'ischermu seguru cuat sos cuntenutos de s\'aplicatzione cando mudas de aplicatzione e blocat sas ischermadas Visualizatzione @@ -381,7 +380,6 @@ Pro Tachiyomi b\'at bisòngiu de WebView Litzèntzias a còdighe abertu Situ web - Incarca in segus torra pro essire Iscarrigados ebbia Cap. %1$s - %2$s Ùrtima impreada diff --git a/i18n/src/main/res/values-sdh/strings.xml b/i18n/src/main/res/values-sdh/strings.xml index 5bc6ac7ee..65edfe421 100644 --- a/i18n/src/main/res/values-sdh/strings.xml +++ b/i18n/src/main/res/values-sdh/strings.xml @@ -7,7 +7,6 @@ سازکارییەکان لیستی داونلۆد تۆماری ڕابردوو - بکەرەوەTachiyomi دڵنیابوونەوە تا گۆڕانکاری بکرێت ئاماژەکردنی پێشوو وەک خوێندراو نیشانکردنی چاپتەر @@ -51,7 +50,6 @@ داونلۆد هیچ کاتیگۆرییەکت نییە. دەست بنێ بە دوگمەی زیادە تا کاتیگۆرییەک بۆ ڕێکخستنی تۆماری ڕابردووت درووست بکەیت. سڕینەوە - دووبارە گەڕانەوە بکە بۆ چوونە دەرەوە هێج نوێکارییەک نییە لەم دواییانەدا سەرچاوەکان هیچ مانگایەکت لەم دواییانە نەخوێندووەتەوە diff --git a/i18n/src/main/res/values-sk/strings.xml b/i18n/src/main/res/values-sk/strings.xml index 2bbde5925..699246092 100644 --- a/i18n/src/main/res/values-sk/strings.xml +++ b/i18n/src/main/res/values-sk/strings.xml @@ -301,7 +301,6 @@ Najnovšia kapitola Zobraziť kapitoly Zrušiť všetky - Odomknúť Tachiyomi Menu Najnovšie Najstaršie @@ -323,7 +322,6 @@ Hľadať v nastaveniach Dátum pridaný Dátum načítania kapitoly - Stlačte tlačidlo späť znova pre ukončenie Prihlásiť sa pre potvrdenie zmien Predvolené Zdroje diff --git a/i18n/src/main/res/values-sq/strings.xml b/i18n/src/main/res/values-sq/strings.xml index 12be2cb40..f992c611b 100644 --- a/i18n/src/main/res/values-sq/strings.xml +++ b/i18n/src/main/res/values-sq/strings.xml @@ -116,11 +116,9 @@ Sipas alfabetit Totali i kapitujve Paralajmërim - Zhblloko Tachiyomi Totali i hyrjeve Leximi i fundit Vërtetoni për të konfirmuar ndryshimin - Shtypni përsëri për të dalë Menuja Filtro Sipas numrit të kapitullit diff --git a/i18n/src/main/res/values-sr/strings.xml b/i18n/src/main/res/values-sr/strings.xml index 89c666787..0a66772ff 100644 --- a/i18n/src/main/res/values-sr/strings.xml +++ b/i18n/src/main/res/values-sr/strings.xml @@ -97,11 +97,11 @@ Неповерљиво Обриши Неповерљив додатак - Овај додатак је потписан са неповерљивим сертификатом и није активиран. + Овај додатак је потписан са непоузданим сертификатом и није активиран. \n -\nЗлонамерни додатак може прочитати све податке за пријаву који су спремљени у програму Тachiyomi или извршити произвољни код. +\nЗлонамерни додатак може прочитати све податке за пријаву или извршити произвољни код. \n -\nВерујући овом сертификату, прихваташ те ризике. +\nВерујући овом сертификату прихватате ове ризике. Цео екран Анимације при промени странице Брзина анимације двоклика @@ -257,7 +257,6 @@ Безбедносни екран Ажурирања на чекању - Откључај Tachiyomi Прикажи Сакриј обавештења Искључи оптимизацију коришћења батерије @@ -279,7 +278,6 @@ Закачи Изабери обрнуто Мени - Притисните поново назад да бисте изашли Само преузето Немате категорија. Додирните дугме плус да бисте направили нову категорију за организовање колекције. Поглавља %1$s @@ -364,7 +362,7 @@ Грешка Преузимања Ажурирајте WebView за бољу компатибилност - За Tachiyomi је потребан WebView + WebView је потребан како би апликација функционисала Неуспешно заобилажење Cloudflare-а Доступно је %d ново ажурирање додатака @@ -394,7 +392,7 @@ Прикажи начин читања Може садржати садржај за одрасле (18+) 18+ - Овај додатак није из званичне листе Таchiyomi додатака. + Овај додатак није из званичне листе. Незванично %d категорија @@ -831,4 +829,8 @@ Следеће очекивано ажурирање Синхронизовање колекције Месечно преузимање (28 дана) + Откључај %s + Нема везе са интернетом + HTTP %d, погледај веб сајт у WebView + %s је недоступан \ No newline at end of file diff --git a/i18n/src/main/res/values-sv/strings.xml b/i18n/src/main/res/values-sv/strings.xml index aab5ca38a..509b508f9 100644 --- a/i18n/src/main/res/values-sv/strings.xml +++ b/i18n/src/main/res/values-sv/strings.xml @@ -99,7 +99,7 @@ Opålitlig extension Detta tillägg tecknades med ett otillförlitligt certifikat och var inte aktiverat. \n -\nEtt skadligt tillägg kan läsa inloggningsuppgifter som är lagrade i Tachiyomi eller utföra godtycklig kod. +\nEtt skadligt tillägg kan läsa lagrade inloggningsuppgifter eller utföra godtycklig kod. \n \nGenom att lita på detta certifikat accepterar du dessa risker. Fullskärm @@ -328,7 +328,6 @@ Det gick inte att kringgå Cloudflare Uppdatera WebView-appen för bättre kompatibilitet Kapiteluppdateringar - Lås upp Tachiyomi Säker skärm döljer appinnehållet när du byter app och blockerar skärmdumpar Skärmvisning @@ -378,8 +377,7 @@ Välj omvänd Mindre Mer - Tryck tillbaka igen för att gå ur - WebView krävs för Tachiyomi + WebView krävs för att appen ska fungera Kapitel %1$s - %2$s Lokal källa guide Senast använd @@ -418,7 +416,7 @@ Saknade källor: Säkerhetskopian innehåller inga biblioteksposter. Ogiltig säkerhetskopia - Detta tillägg kommer inte från den officiella Tachiyomi-tilläggslistan. + Detta tillägg är inte från den officiella listan. Inofficiell Sök efter nytt omslag och detaljer när du uppdaterar biblioteket Uppdatera metadata automatiskt @@ -818,4 +816,5 @@ Ingen internet anslutning HTTP %d, kolla på webbsida i WebView Kunde inte nå %s + Lås upp %s \ No newline at end of file diff --git a/i18n/src/main/res/values-te/strings.xml b/i18n/src/main/res/values-te/strings.xml index 633a47469..1ee8a80af 100644 --- a/i18n/src/main/res/values-te/strings.xml +++ b/i18n/src/main/res/values-te/strings.xml @@ -45,8 +45,6 @@ శోధకము వివరాలపట్టిక అమరికలు - నిష్క్రమించడానికి బ్యాక్ చిహ్నాన్ని మళ్ళీ నొక్కండి - టచియోమిని తెరవండి చరిత్ర కంట కనిపెట్టుట అధ్యాయాలు diff --git a/i18n/src/main/res/values-th/strings.xml b/i18n/src/main/res/values-th/strings.xml index e4b39fd7a..c6550e937 100644 --- a/i18n/src/main/res/values-th/strings.xml +++ b/i18n/src/main/res/values-th/strings.xml @@ -104,7 +104,7 @@ ส่วนขยายที่ไม่น่าเชื่อถือ ส่วนขยายนี้ลงนามด้วยใบรับรองที่ไม่น่าเชื่อถือและจะไม่ถูกเปิดใช้งาน \n -\nส่วนขยายที่เป็นอันตรายสามารถอ่านข้อมูลการเข้าสู่ระบบที่จัดเก็บไว้ใน Tachiyomi หรือเรียกใช้โค้ดโดยอำเภอใจ +\nส่วนขยายที่เป็นอันตรายสามารถอ่านข้อมูลการเข้าสู่ระบบที่จัดเก็บไว้ หรือเรียกใช้โค้ดโดยอำเภอใจ \n \nการเชื่อถือใบรับรองนี้แสดงว่าคุณยอมรับความเสี่ยงเหล่านี้ เต็มหน้าจอ @@ -325,7 +325,7 @@ แสดงตำแหน่งโซนการแตะ แหล่งที่มาจากส่วนขยายนี้อาจมีเนื้อหา NSFW (18+) 18+ - ส่วนขยายนี้ไม่ได้มาจากรายการส่วนขยายทางการของ Tachiyomi + ส่วนขยายนี้ไม่ได้มาจากรายการทางการ ส่วนขยายนี้ไม่สามารถใช้ได้อีกต่อไป แอปอาจทำงานไม่ถูกต้องและอาจทำให้เกิดปัญหากับแอปได้ ขอแนะนำให้ถอนการติดตั้งออก ไม่เป็นทางการ ล้าสมัย @@ -395,8 +395,6 @@ ตอนล่าสุด ติดตามแล้ว เมนู - กดกลับอีกครั้งเพื่อออก - ปลดล็อก Tachiyomi แหล่งที่มา เพิ่มเติม ช่องว่างด้านข้าง @@ -525,7 +523,7 @@ ความคืบหน้า อัปเดตการตั้งค่าตอนเริ่มต้นแล้ว โปรดอัปเดตแอพ WebView เพื่อความเข้ากันได้ที่ดีขึ้น - Tachiyomi จำเป็นต้องใช้ WebView + แอปจำเป็นต้องใช้ WebView เพื่อให้ทำงานได้ ไม่สามารถเลี่ยงผ่าน Cloudflare ได้ มีการอัปเดตส่วนขยาย %d รายการพร้อมใช้งาน @@ -799,4 +797,8 @@ ไม่สามารถสร้างไฟล์สำรองข้อมูล มีลิขสิทธิ์แล้ว - ไม่มีตอนให้แสดง เข้าสู่ระบบการติดตาม + ปลดล็อก %s + ไม่มีการเชื่อมต่ออินเทอร์เน็ต + HTTP %d, ดูเว็บไซต์ใน WebView + ไม่สามารถเข้าถึง %s ได้ \ No newline at end of file diff --git a/i18n/src/main/res/values-tr/strings.xml b/i18n/src/main/res/values-tr/strings.xml index b9ee6a9d4..e2cfd0824 100644 --- a/i18n/src/main/res/values-tr/strings.xml +++ b/i18n/src/main/res/values-tr/strings.xml @@ -99,7 +99,7 @@ Güvenilmeyen uzantı Bu uzantı güvenilmeyen bir sertifika ile imzalanmış ve etkinleştirilmedi. \n -\nKötü niyetli bir uzantı, Tachiyomi\'de saklanan her giriş kimlik bilgisini okuyabilir veya rastgele kod yürütebilir. +\nKötü niyetli bir uzantı, saklanan her giriş kimlik bilgisini okuyabilir veya rastgele kod yürütebilir. \n \nBu sertifikaya güvenerek bu riskleri kabul etmiş oluyorsunuz. Tam Ekran @@ -328,7 +328,6 @@ Cloudflare baypas edilemedi Daha iyi uyumluluk için lütfen WebView\'i güncelleyin Bölüm güncellemeleri - Tachiyomi\'nin kilidi aç Güvenli ekran, uygulamalar arasında geçiş yaparken uygulama içeriğini gizler ve ekran görüntüsü alınmasını engeller Ekran @@ -379,9 +378,8 @@ Daha az Daha fazla Web sitesi - WebView, Tachiyomi için gereklidir + Web Görünümü, uygulamanın işlevselliği için gereklidir Açık kaynak lisansları - Çıkmak için yeniden geriye basın Yalnızca indirilen Böl. %1$s - %2$s Yedek geri yüklenemedi @@ -413,7 +411,7 @@ Bölüm ilerlemesini, izleme hizmetlerinde güncellemek için tek yönlü eşitleme. Her girdinin izleme düğmesinden, izlemeyi ayarlayın. Kitaplıktakilerin kapaklarını yenile - Bu uzantı resmi Tachiyomi uzantıları dizelgesinden değil. + Bu uzantı resmi dizelgeden değil. Resmi olmayan Yükleme tarihine göre Veri @@ -808,4 +806,15 @@ Güncelleme aralığını ayarla Sonuç var İndirilenleri sil + Yedekleme dosyası oluşturulamadı + Lisanslı - Gösterilecek bölüm yok + İndirilenler dizini geçersiz kılındı + Cloudflare\'le ilgili yardım için tıklayın + %s verisine erişilemedi + İzleme girişi + Kitaplık eşleşmesi tamamlandı + HTTP %d, siteyi Web Görünümünde denetle + Genel ağ bağlantısı yok + Kitaplık eşleştiriliyor + Aç: %s \ No newline at end of file diff --git a/i18n/src/main/res/values-uk/strings.xml b/i18n/src/main/res/values-uk/strings.xml index 74c61e397..33976dc75 100644 --- a/i18n/src/main/res/values-uk/strings.xml +++ b/i18n/src/main/res/values-uk/strings.xml @@ -330,7 +330,6 @@ Не вдалось обійти Cloudflare Будь ласка, оновіть WebView для кращої сумісності Оновлення розділів - Розблокувати Tachiyomi Ховати вміст застосунку при перемиканні застосунків та блокувати скріншоти Відображення @@ -390,7 +389,6 @@ WebView необхідний для Tachiyomi Ліцензії з відкритим кодом Сторінка - Натисніть ще раз, щоб вийти Тільки завантажені Сірий Зменшує смугастість, але може вплинути на продуктивність diff --git a/i18n/src/main/res/values-uz/strings.xml b/i18n/src/main/res/values-uz/strings.xml index 8dd313fc0..9b2703dbe 100644 --- a/i18n/src/main/res/values-uz/strings.xml +++ b/i18n/src/main/res/values-uz/strings.xml @@ -35,8 +35,6 @@ Filtr Menyu Sozlamalar - Chiqish uchun orqaga tugmasini bosing - Tachiyomini ochish Tarix Kuzatish Boblar diff --git a/i18n/src/main/res/values-vi/strings.xml b/i18n/src/main/res/values-vi/strings.xml index ecbb35bb4..e37aebf1b 100644 --- a/i18n/src/main/res/values-vi/strings.xml +++ b/i18n/src/main/res/values-vi/strings.xml @@ -386,7 +386,6 @@ Đảo ngược lựa chọn Chương mới nhất Mục chính - Mở Khoá Tachiyomi Nguồn Thêm Đồng bộ một chiều để cập nhật tiến trình chương trong các dịch vụ theo dõi. Thiết lập theo dõi cho các truyện riêng lẻ từ nút theo dõi. @@ -411,7 +410,6 @@ Tắt tất cả Bật tất cả Ngày thêm - Nhấn trở lại lần nữa để thoát Bản sao lưu không chứa truyện nào. Tệp sao lưu không hợp lệ Thêm vào thư viện @@ -818,4 +816,5 @@ Cập nhật dự kiến tiếp theo Nhấn vào đây để được trợ giúp về Cloudflare Chưa công bố + Mở khoá %s \ No newline at end of file diff --git a/i18n/src/main/res/values-zh-rCN/strings.xml b/i18n/src/main/res/values-zh-rCN/strings.xml index 106132330..2a32f659f 100644 --- a/i18n/src/main/res/values-zh-rCN/strings.xml +++ b/i18n/src/main/res/values-zh-rCN/strings.xml @@ -324,7 +324,6 @@ 待更新 无法绕过 Cloudflare 请更新 WebView 应用以获得更好的兼容性 - 解锁 Tachiyomi 阻止截屏,并在切换后台时隐藏预览图 显示 章节更新 @@ -374,7 +373,6 @@ 展开 开源许可证 官网 - 再按一次退出 添加到书架 在书架中 仅限已下载内容 diff --git a/i18n/src/main/res/values-zh-rTW/strings.xml b/i18n/src/main/res/values-zh-rTW/strings.xml index 264713803..6fdde8a91 100644 --- a/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/i18n/src/main/res/values-zh-rTW/strings.xml @@ -262,11 +262,11 @@ 信任 不信任 不信任的擴充套件 - 這個擴充套件的憑證並不可靠,且尚未被啟用。 + 此擴充功能使用未受信任的憑證簽署,並未啟用。 \n -\n惡意的擴充套件可能存取任何儲存於 Tachiyomi 中的登錄憑證,或執行任意的程式碼。 +\n惡意擴充功能可能會讀取任何已儲存的登入憑證或執行任意程式碼。 \n -\n信任這個憑證,即表示你願意承擔上述風險。 +\n通過信任此憑證,您接受這些風險。 最後閱畢的章節 最大備份保留數 不在書櫃中的作品閱讀進度將被清除,你確定嗎? @@ -303,7 +303,6 @@ 深色模式 開啟 日期格式 - 再按一次以離開 將套用至你書櫃中的作品 僅限下載內容 開放原始碼授權 @@ -317,7 +316,6 @@ 永不 立即 閒置時鎖定 - 解除鎖定 Tachiyomi 上鎖應用程式 在切換應用程式時隱藏預覽,並禁止擷取螢幕畫面。 防窺畫面 @@ -347,7 +345,7 @@ 最近使用 本機來源入門指南 請更新 WebView 以獲得更佳的相容性 - WebView 為 Tachiyomi 的必要元件 + 應用程式運作需要 WebView 反向選擇 自動重新整理中繼資料 更新書櫃時一併檢查封面與簡介是否有更動 @@ -417,7 +415,7 @@ 歷時 %1$s,出現 %2$s 個錯誤 %02d 分 %02d 秒 - 這個擴充套件不是由 Tachiyomi 所提供。 + 此擴充功能不在官方清單中。 非官方 第 %1$s 章 - %2$s @@ -802,4 +800,5 @@ HTTP %d,請在 WebView 中檢查網站 沒有網際網路連線 無法連上 %s + 解鎖 %s \ No newline at end of file From f5e0cee36cae3aed564b89a31317eb99026e4090 Mon Sep 17 00:00:00 2001 From: Soitora Date: Mon, 11 Sep 2023 00:11:00 +0200 Subject: [PATCH 19/59] Change website URLs to reflect changes (#9916) Change website URLs --- .github/ISSUE_TEMPLATE.md | 2 +- .github/ISSUE_TEMPLATE/config.yml | 4 ++-- .github/ISSUE_TEMPLATE/report_issue.yml | 2 +- .github/workflows/issue_moderator.yml | 2 +- CONTRIBUTING.md | 2 +- README.md | 2 +- app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt | 2 +- .../more/settings/screen/SettingsTrackingScreen.kt | 2 +- .../presentation/more/settings/screen/about/AboutScreen.kt | 2 +- .../eu/kanade/presentation/webview/WebViewScreenContent.kt | 2 +- .../java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt | 2 +- .../eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt | 4 ++-- .../eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt | 2 +- .../browse/extension/details/ExtensionDetailsScreenModel.kt | 2 +- .../tachiyomi/ui/browse/migration/sources/MigrateSourceTab.kt | 2 +- .../main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt | 2 +- core/src/main/java/tachiyomi/core/Constants.kt | 2 +- .../androidMain/kotlin/tachiyomi/source/local/LocalSource.kt | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 0d9d67163..3e311f12f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -5,7 +5,7 @@ I acknowledge that: - I have updated: - To the latest version of the app (stable is v0.14.6) - All extensions -- I have gone through the FAQ (https://tachiyomi.org/help/faq/) and troubleshooting guide (https://tachiyomi.org/help/guides/troubleshooting/) +- I have gone through the FAQ (https://tachiyomi.org/docs/faq/general) and troubleshooting guide (https://tachiyomi.org/docs/guides/troubleshooting/) - If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions - I have searched the existing issues and this is new ticket **NOT** a duplicate or related to another open or closed issue - I will fill out the title and the information in this template diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0922c459d..dddf1e374 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -4,8 +4,8 @@ contact_links: url: https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose about: Issues and requests for extensions and sources should be opened in the tachiyomi-extensions repository instead - name: 📦 Tachiyomi extensions - url: https://tachiyomi.org/extensions + url: https://tachiyomi.org/extensions/ about: List of all available extensions with download links - name: 🖥️ Tachiyomi website - url: https://tachiyomi.org/help/ + url: https://tachiyomi.org/ about: Guides, troubleshooting, and answers to common questions diff --git a/.github/ISSUE_TEMPLATE/report_issue.yml b/.github/ISSUE_TEMPLATE/report_issue.yml index 460e43d82..e80993914 100644 --- a/.github/ISSUE_TEMPLATE/report_issue.yml +++ b/.github/ISSUE_TEMPLATE/report_issue.yml @@ -96,7 +96,7 @@ body: required: true - label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose). required: true - - label: I have gone through the [FAQ](https://tachiyomi.org/help/faq/) and [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/). + - label: I have gone through the [FAQ](https://tachiyomi.org/docs/faq/general) and [troubleshooting guide](https://tachiyomi.org/docs/guides/troubleshooting/). required: true - label: I have updated the app to version **[0.14.6](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**. required: true diff --git a/.github/workflows/issue_moderator.yml b/.github/workflows/issue_moderator.yml index 8c88132d0..8e937956c 100644 --- a/.github/workflows/issue_moderator.yml +++ b/.github/workflows/issue_moderator.yml @@ -39,7 +39,7 @@ jobs: "regex": ".*(?:fail(?:ed|ure|s)?|can\\s*(?:no|')?t|(?:not|un).*able|(?Issues -1. **Before reporting a new issue, take a look at the [FAQ](https://tachiyomi.org/help/faq/), the [changelog](https://github.com/tachiyomiorg/tachiyomi/releases) and the already opened [issues](https://github.com/tachiyomiorg/tachiyomi/issues).** +1. **Before reporting a new issue, take a look at the [FAQ](https://tachiyomi.org/docs/faq/general), the [changelog](https://tachiyomi.org/changelogs/) and the already opened [issues](https://github.com/tachiyomiorg/tachiyomi/issues).** 2. If you are unsure, ask here: [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi) diff --git a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt index 076ef940d..8502f01a3 100644 --- a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt @@ -62,7 +62,7 @@ fun MoreScreen( WarningBanner( textRes = R.string.fdroid_warning, modifier = Modifier.clickable { - uriHandler.openUri("https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version") + uriHandler.openUri("https://tachiyomi.org/docs/faq/general#migrating-from-f-droid") }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt index 3b4df1e0b..d57034536 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt @@ -70,7 +70,7 @@ object SettingsTrackingScreen : SearchableSettings { @Composable override fun RowScope.AppBarAction() { val uriHandler = LocalUriHandler.current - IconButton(onClick = { uriHandler.openUri("https://tachiyomi.org/help/guides/tracking/") }) { + IconButton(onClick = { uriHandler.openUri("https://tachiyomi.org/docs/guides/tracking") }) { Icon( imageVector = Icons.Outlined.HelpOutline, contentDescription = stringResource(R.string.tracking_guide), diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt index 6f42edb7a..61c0b4ae2 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt @@ -149,7 +149,7 @@ object AboutScreen : Screen() { item { TextPreferenceWidget( title = stringResource(R.string.help_translate), - onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/help/contribution/#translation") }, + onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/docs/contribution#translation") }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt index 3a97d57ec..5f88a4fe3 100644 --- a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt +++ b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt @@ -175,7 +175,7 @@ fun WebViewScreenContent( WarningBanner( textRes = R.string.information_cloudflare_help, modifier = Modifier.clickable { - uriHandler.openUri("https://tachiyomi.org/help/guides/troubleshooting/#solving-cloudflare-issues") + uriHandler.openUri("https://tachiyomi.org/docs/guides/troubleshooting/#cloudflare") }, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt index cdca75770..f5e1b88b4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt @@ -497,7 +497,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet private const val WORK_NAME_AUTO = "LibraryUpdate-auto" private const val WORK_NAME_MANUAL = "LibraryUpdate-manual" - private const val ERROR_LOG_HELP_URL = "https://tachiyomi.org/help/guides/troubleshooting" + private const val ERROR_LOG_HELP_URL = "https://tachiyomi.org/docs/guides/troubleshooting/" private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt index 0c4606a4d..b1c3401bf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt @@ -329,11 +329,11 @@ class LibraryUpdateNotifier(private val context: Context) { } companion object { - const val HELP_WARNING_URL = "https://tachiyomi.org/help/faq/#why-does-the-app-warn-about-large-bulk-updates-and-downloads" + const val HELP_WARNING_URL = "https://tachiyomi.org/docs/faq/application/library#why-am-i-warned-about-large-bulk-updates-and-downloads" } } private const val NOTIF_MAX_CHAPTERS = 5 private const val NOTIF_TITLE_MAX_LEN = 45 private const val NOTIF_ICON_SIZE = 192 -private const val HELP_SKIPPED_URL = "https://tachiyomi.org/help/faq/#why-does-global-update-skip-some-entries" +private const val HELP_SKIPPED_URL = "https://tachiyomi.org/docs/faq/application/library#why-does-global-update-skip-certain-entries" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt index 7c0794bc7..f41acad65 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt @@ -143,7 +143,7 @@ internal class AppUpdateNotifier(private val context: Context) { setContentTitle(context.getString(R.string.update_check_notification_update_available)) setContentText(context.getString(R.string.update_check_fdroid_migration_info)) setSmallIcon(R.drawable.ic_tachi) - setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version")) + setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/docs/faq/general#migrating-from-f-droid")) } notificationBuilder.show(Notifications.ID_APP_UPDATE_PROMPT) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt index 1ad0faec4..5596c3296 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt @@ -102,7 +102,7 @@ class ExtensionDetailsScreenModel( val extension = state.value.extension ?: return "" if (!extension.hasReadme) { - return "https://tachiyomi.org/help/faq/#extensions" + return "https://tachiyomi.org/docs/faq/extensions" } val pkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.") diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceTab.kt index 14dcd9756..fe53ccfad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceTab.kt @@ -31,7 +31,7 @@ fun Screen.migrateSourceTab(): TabContent { title = stringResource(R.string.migration_help_guide), icon = Icons.Outlined.HelpOutline, onClick = { - uriHandler.openUri("https://tachiyomi.org/help/guides/source-migration/") + uriHandler.openUri("https://tachiyomi.org/docs/guides/source-migration") }, ), ), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt index cde9762d5..5469a11a8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt @@ -158,7 +158,7 @@ object LibraryTab : Tab { EmptyScreenAction( stringResId = R.string.getting_started_guide, icon = Icons.Outlined.HelpOutline, - onClick = { handler.openUri("https://tachiyomi.org/help/guides/getting-started") }, + onClick = { handler.openUri("https://tachiyomi.org/docs/guides/getting-started") }, ), ), ) diff --git a/core/src/main/java/tachiyomi/core/Constants.kt b/core/src/main/java/tachiyomi/core/Constants.kt index 156ed6101..c5631535f 100644 --- a/core/src/main/java/tachiyomi/core/Constants.kt +++ b/core/src/main/java/tachiyomi/core/Constants.kt @@ -1,7 +1,7 @@ package tachiyomi.core object Constants { - const val URL_HELP = "https://tachiyomi.org/help/" + const val URL_HELP = "https://tachiyomi.org/docs/guides/troubleshooting/" const val MANGA_EXTRA = "manga" diff --git a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt index 42879d559..2092eae99 100644 --- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt +++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt @@ -348,7 +348,7 @@ actual class LocalSource( companion object { const val ID = 0L - const val HELP_URL = "https://tachiyomi.org/help/guides/local-manga/" + const val HELP_URL = "https://tachiyomi.org/docs/guides/local-series/" private val LATEST_THRESHOLD = 7.days.inWholeMilliseconds } From ccc9a5a052b133174f8ba361490386ff0361283e Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 10 Sep 2023 18:16:53 -0400 Subject: [PATCH 20/59] Update website links --- CONTRIBUTING.md | 2 +- app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt | 2 +- .../presentation/more/settings/screen/about/AboutScreen.kt | 4 ++-- .../eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt | 4 ++-- .../eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt | 2 +- .../browse/extension/details/ExtensionDetailsScreenModel.kt | 2 +- .../androidMain/kotlin/tachiyomi/source/local/LocalSource.kt | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1768a457d..15d4d1b3a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,7 +30,7 @@ Before you start, please note that the ability to use following technologies is # Translations -Translations are done externally via Weblate. See [our website](https://tachiyomi.org/docs/contribution#translation) for more details. +Translations are done externally via Weblate. See [our website](https://tachiyomi.org/docs/contribute#translation) for more details. # Forks diff --git a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt index 8502f01a3..5ef863c51 100644 --- a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt @@ -62,7 +62,7 @@ fun MoreScreen( WarningBanner( textRes = R.string.fdroid_warning, modifier = Modifier.clickable { - uriHandler.openUri("https://tachiyomi.org/docs/faq/general#migrating-from-f-droid") + uriHandler.openUri("https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds") }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt index 61c0b4ae2..af3835987 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt @@ -149,7 +149,7 @@ object AboutScreen : Screen() { item { TextPreferenceWidget( title = stringResource(R.string.help_translate), - onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/docs/contribution#translation") }, + onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/docs/contribute#translation") }, ) } @@ -163,7 +163,7 @@ object AboutScreen : Screen() { item { TextPreferenceWidget( title = stringResource(R.string.privacy_policy), - onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/privacy") }, + onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/privacy/") }, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt index b1c3401bf..299889b8c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt @@ -329,11 +329,11 @@ class LibraryUpdateNotifier(private val context: Context) { } companion object { - const val HELP_WARNING_URL = "https://tachiyomi.org/docs/faq/application/library#why-am-i-warned-about-large-bulk-updates-and-downloads" + const val HELP_WARNING_URL = "https://tachiyomi.org/docs/faq/library#why-am-i-warned-about-large-bulk-updates-and-downloads" } } private const val NOTIF_MAX_CHAPTERS = 5 private const val NOTIF_TITLE_MAX_LEN = 45 private const val NOTIF_ICON_SIZE = 192 -private const val HELP_SKIPPED_URL = "https://tachiyomi.org/docs/faq/application/library#why-does-global-update-skip-certain-entries" +private const val HELP_SKIPPED_URL = "https://tachiyomi.org/docs/faq/library#why-is-global-update-skipping-entries" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt index f41acad65..728967654 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt @@ -143,7 +143,7 @@ internal class AppUpdateNotifier(private val context: Context) { setContentTitle(context.getString(R.string.update_check_notification_update_available)) setContentText(context.getString(R.string.update_check_fdroid_migration_info)) setSmallIcon(R.drawable.ic_tachi) - setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/docs/faq/general#migrating-from-f-droid")) + setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds")) } notificationBuilder.show(Notifications.ID_APP_UPDATE_PROMPT) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt index 5596c3296..c88ea5b42 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt @@ -102,7 +102,7 @@ class ExtensionDetailsScreenModel( val extension = state.value.extension ?: return "" if (!extension.hasReadme) { - return "https://tachiyomi.org/docs/faq/extensions" + return "https://tachiyomi.org/docs/faq/browse/extensions" } val pkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.") diff --git a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt index 2092eae99..b74dcbb2d 100644 --- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt +++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt @@ -348,7 +348,7 @@ actual class LocalSource( companion object { const val ID = 0L - const val HELP_URL = "https://tachiyomi.org/docs/guides/local-series/" + const val HELP_URL = "https://tachiyomi.org/docs/guides/local-source/" private val LATEST_THRESHOLD = 7.days.inWholeMilliseconds } From 8824c7dbe392d586b24234f8e4c0a1c944a77328 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 10 Sep 2023 22:36:57 -0400 Subject: [PATCH 21/59] Tweak reading mode and orientation sheet designs --- .../manga/components/MangaBottomActionMenu.kt | 2 +- .../reader/OrientationModeSelectDialog.kt | 40 ++++++++--------- .../reader/ReadingModeSelectDialog.kt | 39 ++++++++-------- i18n/src/main/res/values/strings.xml | 4 +- .../core/components/SettingsItems.kt | 26 ++++++++++- .../components/material/IconToggleButton.kt | 44 +++++++++++++++++++ 6 files changed, 109 insertions(+), 46 deletions(-) create mode 100644 presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt index eac2228f1..fa98e176b 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt @@ -143,7 +143,7 @@ fun MangaBottomActionMenu( if (onMarkPreviousAsReadClicked != null) { Button( title = stringResource(R.string.action_mark_previous_as_read), - icon = ImageVector.vectorResource(id = R.drawable.ic_done_prev_24dp), + icon = ImageVector.vectorResource(R.drawable.ic_done_prev_24dp), toConfirm = confirm[4], onLongClick = { onLongClickItem(4) }, onClick = onMarkPreviousAsReadClicked, diff --git a/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt index 9e277b757..f88a012c0 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt @@ -1,25 +1,25 @@ package eu.kanade.presentation.reader -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material3.FilterChip -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text +import androidx.compose.foundation.lazy.grid.items import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.dp import eu.kanade.domain.manga.model.orientationType import eu.kanade.presentation.components.AdaptiveSheet import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel -import tachiyomi.presentation.core.components.SettingsChipRow -import tachiyomi.presentation.core.components.material.padding +import tachiyomi.presentation.core.components.SettingsIconGrid +import tachiyomi.presentation.core.components.material.IconToggleButton private val orientationTypeOptions = OrientationType.entries.map { it.stringRes to it } @@ -32,22 +32,20 @@ fun OrientationModeSelectDialog( val manga by screenModel.mangaFlow.collectAsState() val orientationType = remember(manga) { OrientationType.fromPreference(manga?.orientationType?.toInt()) } - AdaptiveSheet( - onDismissRequest = onDismissRequest, - ) { - Row( - modifier = Modifier.padding(vertical = 16.dp), - horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), - ) { - SettingsChipRow(R.string.rotation_type) { - orientationTypeOptions.map { (stringRes, it) -> - FilterChip( - selected = it == orientationType, - onClick = { - screenModel.onChangeOrientation(it) + AdaptiveSheet(onDismissRequest = onDismissRequest) { + Box(modifier = Modifier.padding(vertical = 16.dp)) { + SettingsIconGrid(R.string.rotation_type) { + items(orientationTypeOptions) { (stringRes, mode) -> + IconToggleButton( + checked = mode == orientationType, + onCheckedChange = { + screenModel.onChangeOrientation(mode) onChange(stringRes) + onDismissRequest() }, - label = { Text(stringResource(stringRes)) }, + modifier = Modifier.fillMaxWidth(), + imageVector = ImageVector.vectorResource(mode.iconRes), + label = stringResource(stringRes), ) } } diff --git a/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt index 91920d2ec..376d3795c 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt @@ -1,24 +1,25 @@ package eu.kanade.presentation.reader -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material3.FilterChip +import androidx.compose.foundation.lazy.grid.items import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp +import androidx.compose.ui.res.vectorResource import eu.kanade.domain.manga.model.readingModeType import eu.kanade.presentation.components.AdaptiveSheet import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType -import tachiyomi.presentation.core.components.SettingsChipRow +import tachiyomi.presentation.core.components.SettingsIconGrid +import tachiyomi.presentation.core.components.material.IconToggleButton import tachiyomi.presentation.core.components.material.padding private val readingModeOptions = ReadingModeType.entries.map { it.stringRes to it } @@ -32,22 +33,20 @@ fun ReadingModeSelectDialog( val manga by screenModel.mangaFlow.collectAsState() val readingMode = remember(manga) { ReadingModeType.fromPreference(manga?.readingModeType?.toInt()) } - AdaptiveSheet( - onDismissRequest = onDismissRequest, - ) { - Row( - modifier = Modifier.padding(vertical = 16.dp), - horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), - ) { - SettingsChipRow(R.string.pref_category_reading_mode) { - readingModeOptions.map { (stringRes, it) -> - FilterChip( - selected = it == readingMode, - onClick = { - screenModel.onChangeReadingMode(it) + AdaptiveSheet(onDismissRequest = onDismissRequest) { + Box(modifier = Modifier.padding(vertical = MaterialTheme.padding.medium)) { + SettingsIconGrid(R.string.pref_category_reading_mode) { + items(readingModeOptions) { (stringRes, mode) -> + IconToggleButton( + checked = mode == readingMode, + onCheckedChange = { + screenModel.onChangeReadingMode(mode) onChange(stringRes) + onDismissRequest() }, - label = { Text(stringResource(stringRes)) }, + modifier = Modifier.fillMaxWidth(), + imageVector = ImageVector.vectorResource(mode.iconRes), + label = stringResource(stringRes), ) } } diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index b32cfa27a..35e9cb275 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -402,8 +402,8 @@ No animation Normal Fast - Default rotation type - Rotation type + Default rotation + Rotation Free Portrait Reverse portrait diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt index bc7cf7ae3..08bf2d567 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt @@ -12,6 +12,9 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyGridScope +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.material.ContentAlpha import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDownward @@ -42,6 +45,7 @@ import androidx.compose.ui.unit.dp import tachiyomi.core.preference.Preference import tachiyomi.core.preference.TriState import tachiyomi.core.preference.toggle +import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.theme.header import tachiyomi.presentation.core.util.collectAsState @@ -262,7 +266,7 @@ fun TriStateItem( vertical = SettingsItemsPaddings.Vertical, ), verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(24.dp), + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.large), ) { val stateAlpha = if (enabled && onClick != null) 1f else ContentAlpha.disabled @@ -314,7 +318,25 @@ fun SettingsChipRow(@StringRes labelRes: Int, content: @Composable FlowRowScope. end = SettingsItemsPaddings.Horizontal, bottom = SettingsItemsPaddings.Vertical, ), - horizontalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), + content = content, + ) + } +} + +@Composable +fun SettingsIconGrid(@StringRes labelRes: Int, content: LazyGridScope.() -> Unit) { + Column { + HeadingItem(labelRes) + LazyVerticalGrid( + columns = GridCells.Adaptive(128.dp), + modifier = Modifier.padding( + start = SettingsItemsPaddings.Horizontal, + end = SettingsItemsPaddings.Horizontal, + bottom = SettingsItemsPaddings.Vertical, + ), + verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.tiny), + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), content = content, ) } diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt new file mode 100644 index 000000000..27c6590a7 --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt @@ -0,0 +1,44 @@ +package tachiyomi.presentation.core.components.material + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.FilledIconToggleButton +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector + +@Composable +fun IconToggleButton( + checked: Boolean, + onCheckedChange: (Boolean) -> Unit, + modifier: Modifier = Modifier, + imageVector: ImageVector, + label: String, +) { + FilledIconToggleButton( + checked = checked, + onCheckedChange = onCheckedChange, + modifier = modifier, + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .padding(MaterialTheme.padding.small), + ) { + Icon( + imageVector = imageVector, + contentDescription = null, + ) + + Text(label) + } + } +} From f9754f4f587449f6d9c3a31a99b5c39269d561ac Mon Sep 17 00:00:00 2001 From: arkon Date: Mon, 11 Sep 2023 18:39:36 -0400 Subject: [PATCH 22/59] Fix cut off labels in reader sheet toggles --- .../reader/OrientationModeSelectDialog.kt | 2 +- .../presentation/reader/ReadingModeSelectDialog.kt | 2 +- .../core/components/material/IconToggleButton.kt | 14 +++++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt index f88a012c0..0fbe079a9 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt @@ -45,7 +45,7 @@ fun OrientationModeSelectDialog( }, modifier = Modifier.fillMaxWidth(), imageVector = ImageVector.vectorResource(mode.iconRes), - label = stringResource(stringRes), + title = stringResource(stringRes), ) } } diff --git a/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt index 376d3795c..cb11d9950 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt @@ -46,7 +46,7 @@ fun ReadingModeSelectDialog( }, modifier = Modifier.fillMaxWidth(), imageVector = ImageVector.vectorResource(mode.iconRes), - label = stringResource(stringRes), + title = stringResource(stringRes), ) } } diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt index 27c6590a7..2abcc4b39 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt @@ -3,6 +3,7 @@ package tachiyomi.presentation.core.components.material import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.FilledIconToggleButton import androidx.compose.material3.Icon @@ -12,6 +13,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp @Composable fun IconToggleButton( @@ -19,12 +22,13 @@ fun IconToggleButton( onCheckedChange: (Boolean) -> Unit, modifier: Modifier = Modifier, imageVector: ImageVector, - label: String, + title: String, ) { FilledIconToggleButton( checked = checked, onCheckedChange = onCheckedChange, - modifier = modifier, + modifier = modifier + .height(48.dp), ) { Row( horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), @@ -38,7 +42,11 @@ fun IconToggleButton( contentDescription = null, ) - Text(label) + Text( + text = title, + maxLines = 2, + overflow = TextOverflow.Ellipsis, + ) } } } From fe3a710ed0615ac0dd3598c36d91b020f1e173aa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Sep 2023 23:01:03 -0400 Subject: [PATCH 23/59] Update xml.serialization.version to v0.86.2 (#9939) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/kotlinx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index be52d57f9..1f7a93033 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -1,7 +1,7 @@ [versions] kotlin_version = "1.9.10" serialization_version = "1.6.0" -xml_serialization_version = "0.86.1" +xml_serialization_version = "0.86.2" [libraries] reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" } From 66aacade9a2f6c8f28fe62286f83f997c767b1f0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Sep 2023 23:02:19 -0400 Subject: [PATCH 24/59] Update dependency com.google.gms:google-services to v4.4.0 (#9940) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fd2118116..f5febb4d5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ richtext = "0.17.0" [libraries] desugar = "com.android.tools:desugar_jdk_libs:2.0.3" android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2" -google-services-gradle = "com.google.gms:google-services:4.3.15" +google-services-gradle = "com.google.gms:google-services:4.4.0" rxjava = "io.reactivex:rxjava:1.3.8" flowreactivenetwork = "ru.beryukhov:flowreactivenetwork:1.0.4" From 3ad7add3b5c523085a13e8528aa527a7b26c5f59 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Sep 2023 23:06:10 -0400 Subject: [PATCH 25/59] Update dependency io.github.fornewid:material-motion-compose-core to v1.0.7 (#9938) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f5febb4d5..73ee03308 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,7 +57,7 @@ flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013 photoview = "com.github.chrisbanes:PhotoView:2.3.0" directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" insetter = "dev.chrisbanes.insetter:insetter:0.6.1" -compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.0.6" +compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.0.7" compose-simpleicons = "br.com.devsrsouza.compose.icons.android:simple-icons:1.0.0" swipe = "me.saket.swipe:swipe:1.2.0" From e5f83d0c6e0a0e55d35dd3a32e71817447824df0 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 17 Sep 2023 11:03:39 -0400 Subject: [PATCH 26/59] Fix track search item not filling width if content is too short --- .../main/java/eu/kanade/presentation/track/TrackServiceSearch.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackServiceSearch.kt b/app/src/main/java/eu/kanade/presentation/track/TrackServiceSearch.kt index 201f87607..1ac38ecf0 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackServiceSearch.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackServiceSearch.kt @@ -223,6 +223,7 @@ private fun SearchResultItem( val borderColor = if (selected) MaterialTheme.colorScheme.outline else Color.Transparent Box( modifier = Modifier + .fillMaxWidth() .padding(horizontal = 12.dp) .clip(shape) .background(MaterialTheme.colorScheme.surface) From 6663abebaf69241741d0702331857951834ba806 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 17 Sep 2023 12:06:17 -0400 Subject: [PATCH 27/59] Clean up fetch interval tests a bit Also limit the dates we look at to most recent 10 distinct dates only. Closes #9930 --- .../java/eu/kanade/domain/DomainModule.kt | 4 +- .../domain/manga/interactor/UpdateManga.kt | 8 +- .../manga/components/MangaDialogs.kt | 4 +- .../tachiyomi/data/backup/BackupRestorer.kt | 8 +- .../data/library/LibraryUpdateJob.kt | 6 +- .../{SetFetchInterval.kt => FetchInterval.kt} | 45 ++++--- .../manga/interactor/FetchIntervalTest.kt | 127 ++++++++++++++++++ .../manga/interactor/SetFetchIntervalTest.kt | 104 -------------- 8 files changed, 167 insertions(+), 139 deletions(-) rename domain/src/main/java/tachiyomi/domain/manga/interactor/{SetFetchInterval.kt => FetchInterval.kt} (83%) create mode 100644 domain/src/test/java/tachiyomi/domain/manga/interactor/FetchIntervalTest.kt delete mode 100644 domain/src/test/java/tachiyomi/domain/manga/interactor/SetFetchIntervalTest.kt diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 494033c87..f5e428e8a 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -50,6 +50,7 @@ import tachiyomi.domain.history.interactor.GetTotalReadDuration import tachiyomi.domain.history.interactor.RemoveHistory import tachiyomi.domain.history.interactor.UpsertHistory import tachiyomi.domain.history.repository.HistoryRepository +import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga import tachiyomi.domain.manga.interactor.GetFavorites import tachiyomi.domain.manga.interactor.GetLibraryManga @@ -57,7 +58,6 @@ import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.GetMangaWithChapters import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.interactor.ResetViewerFlags -import tachiyomi.domain.manga.interactor.SetFetchInterval import tachiyomi.domain.manga.interactor.SetMangaChapterFlags import tachiyomi.domain.manga.repository.MangaRepository import tachiyomi.domain.release.interactor.GetApplicationRelease @@ -102,7 +102,7 @@ class DomainModule : InjektModule { addFactory { GetNextChapters(get(), get(), get()) } addFactory { ResetViewerFlags(get()) } addFactory { SetMangaChapterFlags(get()) } - addFactory { SetFetchInterval(get()) } + addFactory { FetchInterval(get()) } addFactory { SetMangaDefaultChapterFlags(get(), get(), get()) } addFactory { SetMangaViewerFlags(get()) } addFactory { NetworkToLocalManga(get()) } diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt index 38d6083ff..468ea2389 100644 --- a/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt @@ -3,7 +3,7 @@ package eu.kanade.domain.manga.interactor import eu.kanade.domain.manga.model.hasCustomCover import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.source.model.SManga -import tachiyomi.domain.manga.interactor.SetFetchInterval +import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.MangaUpdate import tachiyomi.domain.manga.repository.MangaRepository @@ -15,7 +15,7 @@ import java.util.Date class UpdateManga( private val mangaRepository: MangaRepository, - private val setFetchInterval: SetFetchInterval, + private val fetchInterval: FetchInterval, ) { suspend fun await(mangaUpdate: MangaUpdate): Boolean { @@ -79,9 +79,9 @@ class UpdateManga( suspend fun awaitUpdateFetchInterval( manga: Manga, dateTime: ZonedDateTime = ZonedDateTime.now(), - window: Pair = setFetchInterval.getWindow(dateTime), + window: Pair = fetchInterval.getWindow(dateTime), ): Boolean { - return setFetchInterval.toMangaUpdateOrNull(manga, dateTime, window) + return fetchInterval.toMangaUpdateOrNull(manga, dateTime, window) ?.let { mangaRepository.update(it) } ?: false } diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt index 1322adb26..94f34eec2 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt @@ -16,7 +16,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import eu.kanade.tachiyomi.R -import tachiyomi.domain.manga.interactor.MAX_FETCH_INTERVAL +import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.presentation.core.components.WheelTextPicker @Composable @@ -67,7 +67,7 @@ fun SetIntervalDialog( contentAlignment = Alignment.Center, ) { val size = DpSize(width = maxWidth / 2, height = 128.dp) - val items = (0..MAX_FETCH_INTERVAL).map { + val items = (0..FetchInterval.MAX_INTERVAL).map { if (it == 0) { stringResource(R.string.label_default) } else { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt index 544c5c18d..765a700c1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt @@ -14,7 +14,7 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.isActive import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.repository.ChapterRepository -import tachiyomi.domain.manga.interactor.SetFetchInterval +import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.track.model.Track import uy.kohesive.injekt.Injekt @@ -31,10 +31,10 @@ class BackupRestorer( ) { private val updateManga: UpdateManga = Injekt.get() private val chapterRepository: ChapterRepository = Injekt.get() - private val setFetchInterval: SetFetchInterval = Injekt.get() + private val fetchInterval: FetchInterval = Injekt.get() private var now = ZonedDateTime.now() - private var currentFetchWindow = setFetchInterval.getWindow(now) + private var currentFetchWindow = fetchInterval.getWindow(now) private var backupManager = BackupManager(context) @@ -103,7 +103,7 @@ class BackupRestorer( val backupMaps = backup.backupBrokenSources.map { BackupSource(it.name, it.sourceId) } + backup.backupSources sourceMapping = backupMaps.associate { it.sourceId to it.name } now = ZonedDateTime.now() - currentFetchWindow = setFetchInterval.getWindow(now) + currentFetchWindow = fetchInterval.getWindow(now) return coroutineScope { // Restore individual manga diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt index f5e1b88b4..734b5180c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt @@ -59,9 +59,9 @@ import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_HAS_U import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_READ import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_OUTSIDE_RELEASE_PERIOD +import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.interactor.GetLibraryManga import tachiyomi.domain.manga.interactor.GetManga -import tachiyomi.domain.manga.interactor.SetFetchInterval import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.toMangaUpdate import tachiyomi.domain.source.model.SourceNotInstalledException @@ -90,7 +90,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet private val getCategories: GetCategories = Injekt.get() private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get() private val refreshTracks: RefreshTracks = Injekt.get() - private val setFetchInterval: SetFetchInterval = Injekt.get() + private val fetchInterval: FetchInterval = Injekt.get() private val notifier = LibraryUpdateNotifier(context) @@ -216,7 +216,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet val failedUpdates = CopyOnWriteArrayList>() val hasDownloads = AtomicBoolean(false) val restrictions = libraryPreferences.autoUpdateMangaRestrictions().get() - val fetchWindow = setFetchInterval.getWindow(ZonedDateTime.now()) + val fetchWindow = fetchInterval.getWindow(ZonedDateTime.now()) coroutineScope { mangaToUpdate.groupBy { it.manga.source }.values diff --git a/domain/src/main/java/tachiyomi/domain/manga/interactor/SetFetchInterval.kt b/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt similarity index 83% rename from domain/src/main/java/tachiyomi/domain/manga/interactor/SetFetchInterval.kt rename to domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt index 8be435047..740c0a150 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/interactor/SetFetchInterval.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt @@ -5,14 +5,12 @@ import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.MangaUpdate import java.time.Instant +import java.time.ZoneId import java.time.ZonedDateTime import java.time.temporal.ChronoUnit import kotlin.math.absoluteValue -const val MAX_FETCH_INTERVAL = 28 -private const val FETCH_INTERVAL_GRACE_PERIOD = 1 - -class SetFetchInterval( +class FetchInterval( private val getChapterByMangaId: GetChapterByMangaId, ) { @@ -29,7 +27,7 @@ class SetFetchInterval( val chapters = getChapterByMangaId.await(manga.id) val interval = manga.fetchInterval.takeIf { it < 0 } ?: calculateInterval( chapters, - dateTime, + dateTime.zone, ) val nextUpdate = calculateNextUpdate(manga, interval, dateTime, currentWindow) @@ -42,33 +40,34 @@ class SetFetchInterval( fun getWindow(dateTime: ZonedDateTime): Pair { val today = dateTime.toLocalDate().atStartOfDay(dateTime.zone) - val lowerBound = today.minusDays(FETCH_INTERVAL_GRACE_PERIOD.toLong()) - val upperBound = today.plusDays(FETCH_INTERVAL_GRACE_PERIOD.toLong()) + val lowerBound = today.minusDays(GRACE_PERIOD) + val upperBound = today.plusDays(GRACE_PERIOD) return Pair(lowerBound.toEpochSecond() * 1000, upperBound.toEpochSecond() * 1000 - 1) } - internal fun calculateInterval(chapters: List, zonedDateTime: ZonedDateTime): Int { - val sortedChapters = chapters - .sortedWith( - compareByDescending { it.dateUpload }.thenByDescending { it.dateFetch }, - ) - .take(50) - - val uploadDates = sortedChapters + internal fun calculateInterval(chapters: List, zone: ZoneId): Int { + val uploadDates = chapters.asSequence() .filter { it.dateUpload > 0L } + .sortedByDescending { it.dateUpload } .map { - ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateUpload), zonedDateTime.zone) + ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateUpload), zone) .toLocalDate() .atStartOfDay() } .distinct() - val fetchDates = sortedChapters + .take(10) + .toList() + + val fetchDates = chapters.asSequence() + .sortedByDescending { it.dateFetch } .map { - ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateFetch), zonedDateTime.zone) + ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateFetch), zone) .toLocalDate() .atStartOfDay() } .distinct() + .take(10) + .toList() val interval = when { // Enough upload date from source @@ -87,7 +86,7 @@ class SetFetchInterval( else -> 7 } - return interval.coerceIn(1, MAX_FETCH_INTERVAL) + return interval.coerceIn(1, MAX_INTERVAL) } private fun calculateNextUpdate( @@ -118,7 +117,7 @@ class SetFetchInterval( } private fun doubleInterval(delta: Int, timeSinceLatest: Int, doubleWhenOver: Int): Int { - if (delta >= MAX_FETCH_INTERVAL) return MAX_FETCH_INTERVAL + if (delta >= MAX_INTERVAL) return MAX_INTERVAL // double delta again if missed more than 9 check in new delta val cycle = timeSinceLatest.floorDiv(delta) + 1 @@ -128,4 +127,10 @@ class SetFetchInterval( delta } } + + companion object { + const val MAX_INTERVAL = 28 + + private const val GRACE_PERIOD = 1L + } } diff --git a/domain/src/test/java/tachiyomi/domain/manga/interactor/FetchIntervalTest.kt b/domain/src/test/java/tachiyomi/domain/manga/interactor/FetchIntervalTest.kt new file mode 100644 index 000000000..468d7eb2d --- /dev/null +++ b/domain/src/test/java/tachiyomi/domain/manga/interactor/FetchIntervalTest.kt @@ -0,0 +1,127 @@ +package tachiyomi.domain.manga.interactor + +import io.kotest.matchers.shouldBe +import io.mockk.mockk +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.parallel.Execution +import org.junit.jupiter.api.parallel.ExecutionMode +import tachiyomi.domain.chapter.model.Chapter +import java.time.ZoneOffset +import java.time.ZonedDateTime +import kotlin.time.Duration +import kotlin.time.Duration.Companion.days +import kotlin.time.Duration.Companion.hours +import kotlin.time.DurationUnit +import kotlin.time.toDuration +import kotlin.time.toJavaDuration + +@Execution(ExecutionMode.CONCURRENT) +class FetchIntervalTest { + + private val testTime = ZonedDateTime.parse("2020-01-01T00:00:00Z") + private val testZoneId = ZoneOffset.UTC + private var chapter = Chapter.create().copy( + dateFetch = testTime.toEpochSecond() * 1000, + dateUpload = testTime.toEpochSecond() * 1000, + ) + + private val fetchInterval = FetchInterval(mockk()) + + @Test + fun `returns default interval of 7 days when not enough distinct days`() { + val chaptersWithUploadDate = (1..50).map { + chapterWithTime(chapter, 1.days) + } + fetchInterval.calculateInterval(chaptersWithUploadDate, testZoneId) shouldBe 7 + + val chaptersWithoutUploadDate = chaptersWithUploadDate.map { + it.copy(dateUpload = 0L) + } + fetchInterval.calculateInterval(chaptersWithoutUploadDate, testZoneId) shouldBe 7 + } + + @Test + fun `returns interval based on more recent chapters`() { + val oldChapters = (1..5).map { + chapterWithTime(chapter, (it * 7).days) // Would have interval of 7 days + } + val newChapters = (1..10).map { + chapterWithTime(chapter, oldChapters.lastUploadDate() + it.days) + } + + val chapters = oldChapters + newChapters + + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 1 + } + + @Test + fun `returns interval of 7 days when multiple chapters in 1 day`() { + val chapters = (1..10).map { + chapterWithTime(chapter, 10.hours) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 7 + } + + @Test + fun `returns interval of 7 days when multiple chapters in 2 days`() { + val chapters = (1..2).map { + chapterWithTime(chapter, 1.days) + } + (1..5).map { + chapterWithTime(chapter, 2.days) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 7 + } + + @Test + fun `returns interval of 1 day when chapters are released every 1 day`() { + val chapters = (1..20).map { + chapterWithTime(chapter, it.days) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 1 + } + + @Test + fun `returns interval of 1 day when delta is less than 1 day`() { + val chapters = (1..20).map { + chapterWithTime(chapter, (15 * it).hours) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 1 + } + + @Test + fun `returns interval of 2 days when chapters are released every 2 days`() { + val chapters = (1..20).map { + chapterWithTime(chapter, (2 * it).days) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 2 + } + + @Test + fun `returns interval with floored value when interval is decimal`() { + val chaptersWithUploadDate = (1..5).map { + chapterWithTime(chapter, (25 * it).hours) + } + fetchInterval.calculateInterval(chaptersWithUploadDate, testZoneId) shouldBe 1 + + val chaptersWithoutUploadDate = chaptersWithUploadDate.map { + it.copy(dateUpload = 0L) + } + fetchInterval.calculateInterval(chaptersWithoutUploadDate, testZoneId) shouldBe 1 + } + + @Test + fun `returns interval of 1 day when chapters are released just below every 2 days`() { + val chapters = (1..20).map { + chapterWithTime(chapter, (43 * it).hours) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 1 + } + + private fun chapterWithTime(chapter: Chapter, duration: Duration): Chapter { + val newTime = testTime.plus(duration.toJavaDuration()).toEpochSecond() * 1000 + return chapter.copy(dateFetch = newTime, dateUpload = newTime) + } + + private fun List.lastUploadDate() = + last().dateUpload.toDuration(DurationUnit.MILLISECONDS) +} diff --git a/domain/src/test/java/tachiyomi/domain/manga/interactor/SetFetchIntervalTest.kt b/domain/src/test/java/tachiyomi/domain/manga/interactor/SetFetchIntervalTest.kt deleted file mode 100644 index 8c329ca22..000000000 --- a/domain/src/test/java/tachiyomi/domain/manga/interactor/SetFetchIntervalTest.kt +++ /dev/null @@ -1,104 +0,0 @@ -package tachiyomi.domain.manga.interactor - -import io.kotest.matchers.shouldBe -import io.mockk.mockk -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.parallel.Execution -import org.junit.jupiter.api.parallel.ExecutionMode -import tachiyomi.domain.chapter.model.Chapter -import java.time.ZonedDateTime -import kotlin.time.Duration -import kotlin.time.Duration.Companion.hours -import kotlin.time.toJavaDuration - -@Execution(ExecutionMode.CONCURRENT) -class SetFetchIntervalTest { - - private val testTime = ZonedDateTime.parse("2020-01-01T00:00:00Z") - private var chapter = Chapter.create().copy( - dateFetch = testTime.toEpochSecond() * 1000, - dateUpload = testTime.toEpochSecond() * 1000, - ) - - private val setFetchInterval = SetFetchInterval(mockk()) - - @Test - fun `calculateInterval returns default of 7 days when less than 3 distinct days`() { - val chapters = (1..2).map { - chapterWithTime(chapter, 10.hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7 - } - - @Test - fun `calculateInterval returns 7 when 5 chapters in 1 day`() { - val chapters = (1..5).map { - chapterWithTime(chapter, 10.hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7 - } - - @Test - fun `calculateInterval returns 7 when 7 chapters in 48 hours, 2 day`() { - val chapters = (1..2).map { - chapterWithTime(chapter, 24.hours) - } + (1..5).map { - chapterWithTime(chapter, 48.hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7 - } - - @Test - fun `calculateInterval returns default of 1 day when interval less than 1`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (15 * it).hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1 - } - - // Normal interval calculation - @Test - fun `calculateInterval returns 1 when 5 chapters in 120 hours, 5 days`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (24 * it).hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1 - } - - @Test - fun `calculateInterval returns 2 when 5 chapters in 240 hours, 10 days`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (48 * it).hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 2 - } - - @Test - fun `calculateInterval returns floored value when interval is decimal`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (25 * it).hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1 - } - - @Test - fun `calculateInterval returns 1 when 5 chapters in 215 hours, 5 days`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (43 * it).hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1 - } - - @Test - fun `calculateInterval returns interval based on fetch time if upload time not available`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (25 * it).hours).copy(dateUpload = 0L) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1 - } - - private fun chapterWithTime(chapter: Chapter, duration: Duration): Chapter { - val newTime = testTime.plus(duration.toJavaDuration()).toEpochSecond() * 1000 - return chapter.copy(dateFetch = newTime, dateUpload = newTime) - } -} From 9e04f14a7be6e3fa069b90a9577798d661fe2c9a Mon Sep 17 00:00:00 2001 From: Soitora Date: Sun, 17 Sep 2023 18:08:12 +0200 Subject: [PATCH 28/59] Run Netlify Build Hook after Release (#9937) * Run Netlify Build Hook after Release * Add if statement * Move if statement to job level instead of step --- .github/workflows/build_push.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 6a1f423a3..e43c229a0 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -104,3 +104,13 @@ jobs: prerelease: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + update-website: + needs: [build] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') && github.repository == 'tachiyomiorg/tachiyomi' + steps: + - name: Trigger Netlify build hook + run: curl -s -X POST -d {} "https://api.netlify.com/build_hooks/${TOKEN}" + env: + TOKEN: ${{ secrets.NETLIFY_HOOK_RELEASE }} From b08d604d2a8ae09e623a4375a75cbc844d26a0fa Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 20 Sep 2023 22:49:15 -0400 Subject: [PATCH 29/59] Consistently use absolute date strings everywhere Closes #9781 --- .../components/RelativeDateHeader.kt | 5 +- .../kanade/presentation/manga/MangaScreen.kt | 3 +- .../ui/updates/UpdatesScreenModel.kt | 3 +- .../tachiyomi/util/lang/DateExtensions.kt | 101 ------------------ i18n/src/main/res/values/strings.xml | 6 -- 5 files changed, 3 insertions(+), 115 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt b/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt index 89bb61b4f..598bad83e 100644 --- a/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt +++ b/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt @@ -3,8 +3,6 @@ package eu.kanade.presentation.components import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import eu.kanade.tachiyomi.util.lang.toRelativeString import tachiyomi.presentation.core.components.ListGroupHeader import java.text.DateFormat import java.util.Date @@ -15,11 +13,10 @@ fun RelativeDateHeader( date: Date, dateFormat: DateFormat, ) { - val context = LocalContext.current ListGroupHeader( modifier = modifier, text = remember { - date.toRelativeString(context, dateFormat) + dateFormat.format(date) }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt index 740ece4a2..352e6aedb 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -63,7 +63,6 @@ import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.source.getNameForMangaInfo import eu.kanade.tachiyomi.ui.manga.ChapterItem import eu.kanade.tachiyomi.ui.manga.MangaScreenModel -import eu.kanade.tachiyomi.util.lang.toRelativeString import eu.kanade.tachiyomi.util.system.copyToClipboard import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.service.missingChaptersCount @@ -740,7 +739,7 @@ private fun LazyListScope.sharedChapterItems( date = chapterItem.chapter.dateUpload .takeIf { it > 0L } ?.let { - Date(it).toRelativeString(context, dateFormat) + dateFormat.format(Date(it)) }, readProgress = chapterItem.chapter.lastPageRead .takeIf { !chapterItem.chapter.read && it > 0L } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt index 6459d6525..6e0c1c474 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt @@ -20,7 +20,6 @@ import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.util.lang.toDateKey -import eu.kanade.tachiyomi.util.lang.toRelativeString import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -384,7 +383,7 @@ class UpdatesScreenModel( val afterDate = after?.item?.update?.dateFetch?.toDateKey() ?: Date(0) when { beforeDate.time != afterDate.time && afterDate.time != 0L -> { - val text = afterDate.toRelativeString(context, dateFormat) + val text = dateFormat.format(afterDate) UpdatesUiModel.Header(text) } // Return null to avoid adding a separator between two items. diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt index 9efcaaa9f..88477e8d5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt @@ -1,14 +1,11 @@ package eu.kanade.tachiyomi.util.lang -import android.content.Context -import eu.kanade.tachiyomi.R import java.text.DateFormat import java.time.Instant import java.time.LocalDateTime import java.time.ZoneId import java.util.Calendar import java.util.Date -import java.util.TimeZone fun Date.toDateTimestampString(dateFormatter: DateFormat): String { val date = dateFormatter.format(this) @@ -45,101 +42,3 @@ fun Long.toDateKey(): Date { cal[Calendar.MILLISECOND] = 0 return cal.time } - -/** - * Convert epoch long to Calendar instance - * - * @return Calendar instance at supplied epoch time. Null if epoch was 0. - */ -fun Long.toCalendar(): Calendar? { - if (this == 0L) { - return null - } - val cal = Calendar.getInstance() - cal.timeInMillis = this - return cal -} - -/** - * Convert local time millisecond value to Calendar instance in UTC - * - * @return UTC Calendar instance at supplied time. Null if time is 0. - */ -fun Long.toUtcCalendar(): Calendar? { - if (this == 0L) { - return null - } - val rawCalendar = Calendar.getInstance().apply { - timeInMillis = this@toUtcCalendar - } - return Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { - clear() - set( - rawCalendar.get(Calendar.YEAR), - rawCalendar.get(Calendar.MONTH), - rawCalendar.get(Calendar.DAY_OF_MONTH), - rawCalendar.get(Calendar.HOUR_OF_DAY), - rawCalendar.get(Calendar.MINUTE), - rawCalendar.get(Calendar.SECOND), - ) - } -} - -/** - * Convert UTC time millisecond to Calendar instance in local time zone - * - * @return local Calendar instance at supplied UTC time. Null if time is 0. - */ -fun Long.toLocalCalendar(): Calendar? { - if (this == 0L) { - return null - } - val rawCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { - timeInMillis = this@toLocalCalendar - } - return Calendar.getInstance().apply { - clear() - set( - rawCalendar.get(Calendar.YEAR), - rawCalendar.get(Calendar.MONTH), - rawCalendar.get(Calendar.DAY_OF_MONTH), - rawCalendar.get(Calendar.HOUR_OF_DAY), - rawCalendar.get(Calendar.MINUTE), - rawCalendar.get(Calendar.SECOND), - ) - } -} - -private const val MILLISECONDS_IN_DAY = 86_400_000L - -fun Date.toRelativeString( - context: Context, - dateFormat: DateFormat = DateFormat.getDateInstance(DateFormat.SHORT), -): String { - val now = Date() - val difference = now.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY) - this.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY) - val days = difference.floorDiv(MILLISECONDS_IN_DAY).toInt() - return when { - difference < 0 -> dateFormat.format(this) - difference < MILLISECONDS_IN_DAY -> context.getString(R.string.relative_time_today) - difference < MILLISECONDS_IN_DAY.times(7) -> context.resources.getQuantityString( - R.plurals.relative_time, - days, - days, - ) - else -> dateFormat.format(this) - } -} - -private val Date.timeWithOffset: Long - get() { - return Calendar.getInstance().run { - time = this@timeWithOffset - val dstOffset = get(Calendar.DST_OFFSET) - this@timeWithOffset.time + timeZone.rawOffset + dstOffset - } - } - -fun Long.floorNearest(to: Long): Long { - return this.floorDiv(to) * to -} diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 35e9cb275..67f33acca 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -223,12 +223,6 @@ Show in sources and extensions lists This does not prevent unofficial or potentially incorrectly flagged extensions from surfacing NSFW (18+) content within the app. - Today - - Yesterday - %1$d days ago - - Display Grid size From d4290f6f596dcafbe354eec51875680eb854d179 Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 20 Sep 2023 23:19:00 -0400 Subject: [PATCH 30/59] Fix hide entries in library setting causing browse to not load Fixes #9924 --- .../source/browse/BrowseSourceScreenModel.kt | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt index ff6ad995b..188b148eb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt @@ -9,6 +9,7 @@ import androidx.compose.ui.unit.dp import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.cachedIn +import androidx.paging.filter import androidx.paging.map import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.coroutineScope @@ -30,7 +31,6 @@ import eu.kanade.tachiyomi.util.removeCovers import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow -import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.map @@ -113,25 +113,20 @@ class BrowseSourceScreenModel( /** * Flow of Pager flow tied to [State.listing] */ + private val hideInLibraryItems = sourcePreferences.hideInLibraryItems().get() val mangaPagerFlowFlow = state.map { it.listing } .distinctUntilChanged() .map { listing -> - Pager( - PagingConfig(pageSize = 25), - ) { + Pager(PagingConfig(pageSize = 25)) { getRemoteManga.subscribe(sourceId, listing.query ?: "", listing.filters) }.flow.map { pagingData -> pagingData.map { networkToLocalManga.await(it.toDomainManga(sourceId)) - .let { localManga -> - getManga.subscribe(localManga.url, localManga.source) - } + .let { localManga -> getManga.subscribe(localManga.url, localManga.source) } .filterNotNull() - .filter { localManga -> - !sourcePreferences.hideInLibraryItems().get() || !localManga.favorite - } .stateIn(ioCoroutineScope) } + .filter { !hideInLibraryItems || !it.value.favorite } } .cachedIn(ioCoroutineScope) } From 77a8a4229c9fbf1b601a448dc919f3c5daa94985 Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 22 Sep 2023 16:16:23 -0400 Subject: [PATCH 31/59] Fix duplicate files being created when saving pages on Android 10+ with separate folders setting enabled Fixes #9943 --- .../kanade/tachiyomi/data/saver/ImageSaver.kt | 69 +++++++++++-------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt index 9656c0fd9..7086f1023 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt @@ -1,6 +1,5 @@ package eu.kanade.tachiyomi.data.saver -import android.annotation.SuppressLint import android.content.ContentUris import android.content.Context import android.graphics.Bitmap @@ -28,30 +27,59 @@ class ImageSaver( val context: Context, ) { - @SuppressLint("InlinedApi") fun save(image: Image): Uri { val data = image.data - val type = ImageUtil.findImageType(data) ?: throw Exception("Not an image") + val type = ImageUtil.findImageType(data) ?: throw IllegalArgumentException("Not an image") val filename = DiskUtil.buildValidFilename("${image.name}.${type.extension}") if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || image.location !is Location.Pictures) { return save(data(), image.location.directory(context), filename) } + return saveApi29(image, type, filename, data) + } + + private fun save(inputStream: InputStream, directory: File, filename: String): Uri { + directory.mkdirs() + + val destFile = File(directory, filename) + + inputStream.use { input -> + destFile.outputStream().use { output -> + input.copyTo(output) + } + } + + DiskUtil.scanMedia(context, destFile.toUri()) + + return destFile.getUriCompat(context) + } + + @RequiresApi(Build.VERSION_CODES.Q) + private fun saveApi29( + image: Image, + type: ImageUtil.ImageType, + filename: String, + data: () -> InputStream, + ): Uri { val pictureDir = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) - val folderRelativePath = "${Environment.DIRECTORY_PICTURES}/${context.getString(R.string.app_name)}/" val imageLocation = (image.location as Location.Pictures).relativePath + val relativePath = listOf( + Environment.DIRECTORY_PICTURES, + context.getString(R.string.app_name), + imageLocation, + ).joinToString(File.separator) val contentValues = contentValuesOf( + MediaStore.Images.Media.RELATIVE_PATH to relativePath, MediaStore.Images.Media.DISPLAY_NAME to image.name, MediaStore.Images.Media.MIME_TYPE to type.mime, - MediaStore.Images.Media.RELATIVE_PATH to folderRelativePath + imageLocation, ) - val picture = findUriOrDefault(folderRelativePath, "$imageLocation$filename") { + val picture = findUriOrDefault(relativePath, filename) { context.contentResolver.insert( pictureDir, contentValues, @@ -74,49 +102,34 @@ class ImageSaver( return picture } - private fun save(inputStream: InputStream, directory: File, filename: String): Uri { - directory.mkdirs() - - val destFile = File(directory, filename) - - inputStream.use { input -> - destFile.outputStream().use { output -> - input.copyTo(output) - } - } - - DiskUtil.scanMedia(context, destFile.toUri()) - - return destFile.getUriCompat(context) - } - @RequiresApi(Build.VERSION_CODES.Q) - private fun findUriOrDefault(relativePath: String, imagePath: String, default: () -> Uri): Uri { + private fun findUriOrDefault(path: String, filename: String, default: () -> Uri): Uri { val projection = arrayOf( MediaStore.MediaColumns._ID, MediaStore.MediaColumns.DISPLAY_NAME, - MediaStore.Images.Media.MIME_TYPE, MediaStore.MediaColumns.RELATIVE_PATH, - MediaStore.MediaColumns.DATE_MODIFIED, ) val selection = "${MediaStore.MediaColumns.RELATIVE_PATH}=? AND ${MediaStore.MediaColumns.DISPLAY_NAME}=?" + // Need to make sure it ends with the separator + val normalizedPath = "${path.removeSuffix(File.separator)}${File.separator}" + context.contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, - arrayOf(relativePath, imagePath), + arrayOf(normalizedPath, filename), null, ).use { cursor -> if (cursor != null && cursor.count >= 1) { - cursor.moveToFirst().let { + if (cursor.moveToFirst()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)) - return ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id) } } } + return default() } } From de92b1351f10f9211830358bd225bb768131d6b4 Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 22 Sep 2023 16:42:04 -0400 Subject: [PATCH 32/59] Add WebView-based user agent string to debug info Could probably use this when choosing a user agent later on. --- .../eu/kanade/tachiyomi/util/CrashLogUtil.kt | 2 ++ .../tachiyomi/util/system/WebViewUtil.kt | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt index aa9830de8..c495c7008 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt @@ -4,6 +4,7 @@ import android.content.Context import android.os.Build import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.util.storage.getUriCompat +import eu.kanade.tachiyomi.util.system.WebViewUtil import eu.kanade.tachiyomi.util.system.createFileInCacheDir import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast @@ -35,6 +36,7 @@ class CrashLogUtil(private val context: Context) { Device name: ${Build.DEVICE} Device model: ${Build.MODEL} Device product name: ${Build.PRODUCT} + WebView user agent: ${WebViewUtil.getInferredUserAgent(context)} """.trimIndent() } } diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt index 4fcaaceed..eb1ad9617 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt @@ -14,7 +14,24 @@ import kotlin.coroutines.resume object WebViewUtil { const val SPOOF_PACKAGE_NAME = "org.chromium.chrome" - const val MINIMUM_WEBVIEW_VERSION = 111 + const val MINIMUM_WEBVIEW_VERSION = 114 + + /** + * Uses the WebView's user agent string to create something similar to what Chrome on Android + * would return. + * + * Example of WebView user agent string: + * Mozilla/5.0 (Linux; Android 13; Pixel 7 Build/TQ3A.230901.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36 + * + * Example of Chrome on Android: + * Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.3 + */ + fun getInferredUserAgent(context: Context): String { + return WebView(context) + .getDefaultUserAgentString() + .replace("; Android .*?\\)".toRegex(), "; Android 10; K)") + .replace("Version/.* Chrome/".toRegex(), "Chrome/") + } fun supportsWebView(context: Context): Boolean { try { From 5de72b7d32676fe3d0e9ce2176fe48e29a9f859c Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 23 Sep 2023 12:15:28 -0400 Subject: [PATCH 33/59] Bump dependencies --- .../settings/screen/about/OpenSourceLicensesScreen.kt | 6 +++--- gradle/androidx.versions.toml | 2 +- gradle/libs.versions.toml | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt index e5b94adb8..f1a8ae47c 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt @@ -41,9 +41,9 @@ class OpenSourceLicensesScreen : Screen() { ), onLibraryClick = { val libraryLicenseScreen = OpenSourceLibraryLicenseScreen( - name = it.name, - website = it.website, - license = it.licenses.firstOrNull()?.htmlReadyLicenseContent.orEmpty(), + name = it.library.name, + website = it.library.website, + license = it.library.licenses.firstOrNull()?.htmlReadyLicenseContent.orEmpty(), ) navigator.push(libraryLicenseScreen) }, diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 2d9ba703f..ec3244800 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -27,7 +27,7 @@ guava = "com.google.guava:guava:32.1.2-android" paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging_version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } -benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-beta05" +benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-rc01" test-ext = "androidx.test.ext:junit-ktx:1.2.0-alpha01" test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-alpha01" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0-alpha04" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 73ee03308..091b67f61 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -aboutlib_version = "10.8.3" +aboutlib_version = "10.9.0" okhttp_version = "5.0.0-alpha.11" shizuku_version = "12.2.0" sqlite = "2.3.1" @@ -57,7 +57,7 @@ flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013 photoview = "com.github.chrisbanes:PhotoView:2.3.0" directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" insetter = "dev.chrisbanes.insetter:insetter:0.6.1" -compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.0.7" +compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.1.0" compose-simpleicons = "br.com.devsrsouza.compose.icons.android:simple-icons:1.0.0" swipe = "me.saket.swipe:swipe:1.2.0" @@ -84,13 +84,13 @@ sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref junit = "org.junit.jupiter:junit-jupiter:5.10.0" kotest-assertions = "io.kotest:kotest-assertions-core:5.7.2" -mockk = "io.mockk:mockk:1.13.7" +mockk = "io.mockk:mockk:1.13.8" voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } voyager-tab-navigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" } voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" } -ktlint = "org.jlleitschuh.gradle:ktlint-gradle:11.5.1" +ktlint = "org.jlleitschuh.gradle:ktlint-gradle:11.6.0" [bundles] okhttp = ["okhttp-core", "okhttp-logging", "okhttp-dnsoverhttps"] From 56d2464870cbd59f1e67dab7cf2a359bddfa0f41 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 24 Sep 2023 17:01:26 -0400 Subject: [PATCH 34/59] Bring back simplified relative timestamp setting Except now it's just an on/off toggle for relative up to a week. --- app/build.gradle.kts | 2 +- .../java/eu/kanade/domain/ui/UiPreferences.kt | 2 + .../components/RelativeDateHeader.kt | 10 ++++- .../presentation/history/HistoryScreen.kt | 4 +- .../kanade/presentation/manga/MangaScreen.kt | 17 ++++++-- .../screen/SettingsAppearanceScreen.kt | 14 +++++++ .../presentation/updates/UpdatesScreen.kt | 3 +- .../java/eu/kanade/tachiyomi/Migrations.kt | 6 +++ .../kanade/tachiyomi/ui/manga/MangaScreen.kt | 1 + .../tachiyomi/ui/manga/MangaScreenModel.kt | 1 + .../ui/updates/UpdatesScreenModel.kt | 11 ++++- .../kanade/tachiyomi/ui/updates/UpdatesTab.kt | 1 + .../tachiyomi/util/lang/DateExtensions.kt | 40 +++++++++++++++++++ i18n/src/main/res/values/strings.xml | 9 +++++ .../core/components/AdaptiveSheet.kt | 1 - 15 files changed, 112 insertions(+), 10 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e0658c1d8..93d48d8d4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,7 +22,7 @@ android { defaultConfig { applicationId = "eu.kanade.tachiyomi" - versionCode = 105 + versionCode = 106 versionName = "0.14.6" buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") diff --git a/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt b/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt index ac04a51e0..294812bdc 100644 --- a/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt +++ b/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt @@ -28,6 +28,8 @@ class UiPreferences( fun themeDarkAmoled() = preferenceStore.getBoolean("pref_theme_dark_amoled_key", false) + fun relativeTime() = preferenceStore.getBoolean("relative_time_v2", true) + fun dateFormat() = preferenceStore.getString("app_date_format", "") fun tabletUiMode() = preferenceStore.getEnum("tablet_ui_mode", TabletUiMode.AUTOMATIC) diff --git a/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt b/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt index 598bad83e..2466e2eed 100644 --- a/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt +++ b/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt @@ -3,6 +3,8 @@ package eu.kanade.presentation.components import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import eu.kanade.tachiyomi.util.lang.toRelativeString import tachiyomi.presentation.core.components.ListGroupHeader import java.text.DateFormat import java.util.Date @@ -11,12 +13,18 @@ import java.util.Date fun RelativeDateHeader( modifier: Modifier = Modifier, date: Date, + relativeTime: Boolean, dateFormat: DateFormat, ) { + val context = LocalContext.current ListGroupHeader( modifier = modifier, text = remember { - dateFormat.format(date) + date.toRelativeString( + context, + relativeTime, + dateFormat, + ) }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt b/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt index 3bac670d0..fc755c922 100644 --- a/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt @@ -98,7 +98,8 @@ private fun HistoryScreenContent( onClickDelete: (HistoryWithRelations) -> Unit, preferences: UiPreferences = Injekt.get(), ) { - val dateFormat: DateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat().get()) } + val relativeTime = remember { preferences.relativeTime().get() } + val dateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat().get()) } FastScrollLazyColumn( contentPadding = contentPadding, @@ -118,6 +119,7 @@ private fun HistoryScreenContent( RelativeDateHeader( modifier = Modifier.animateItemPlacement(), date = item.date, + relativeTime = relativeTime, dateFormat = dateFormat, ) } diff --git a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt index 352e6aedb..65963cef3 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -63,6 +63,7 @@ import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.source.getNameForMangaInfo import eu.kanade.tachiyomi.ui.manga.ChapterItem import eu.kanade.tachiyomi.ui.manga.MangaScreenModel +import eu.kanade.tachiyomi.util.lang.toRelativeString import eu.kanade.tachiyomi.util.system.copyToClipboard import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.service.missingChaptersCount @@ -84,6 +85,7 @@ fun MangaScreen( state: MangaScreenModel.State.Success, snackbarHostState: SnackbarHostState, fetchInterval: Int?, + dateRelativeTime: Boolean, dateFormat: DateFormat, isTabletUi: Boolean, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, @@ -139,6 +141,7 @@ fun MangaScreen( MangaScreenSmallImpl( state = state, snackbarHostState = snackbarHostState, + dateRelativeTime = dateRelativeTime, dateFormat = dateFormat, fetchInterval = fetchInterval, chapterSwipeStartAction = chapterSwipeStartAction, @@ -175,6 +178,7 @@ fun MangaScreen( MangaScreenLargeImpl( state = state, snackbarHostState = snackbarHostState, + dateRelativeTime = dateRelativeTime, chapterSwipeStartAction = chapterSwipeStartAction, chapterSwipeEndAction = chapterSwipeEndAction, dateFormat = dateFormat, @@ -214,6 +218,7 @@ fun MangaScreen( private fun MangaScreenSmallImpl( state: MangaScreenModel.State.Success, snackbarHostState: SnackbarHostState, + dateRelativeTime: Boolean, dateFormat: DateFormat, fetchInterval: Int?, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, @@ -282,11 +287,9 @@ private fun MangaScreenSmallImpl( } val animatedTitleAlpha by animateFloatAsState( if (firstVisibleItemIndex > 0) 1f else 0f, - label = "titleAlpha", ) val animatedBgAlpha by animateFloatAsState( if (firstVisibleItemIndex > 0 || firstVisibleItemScrollOffset > 0) 1f else 0f, - label = "bgAlpha", ) MangaToolbar( title = state.manga.title, @@ -427,6 +430,7 @@ private fun MangaScreenSmallImpl( sharedChapterItems( manga = state.manga, chapters = chapters, + dateRelativeTime = dateRelativeTime, dateFormat = dateFormat, chapterSwipeStartAction = chapterSwipeStartAction, chapterSwipeEndAction = chapterSwipeEndAction, @@ -445,6 +449,7 @@ private fun MangaScreenSmallImpl( fun MangaScreenLargeImpl( state: MangaScreenModel.State.Success, snackbarHostState: SnackbarHostState, + dateRelativeTime: Boolean, dateFormat: DateFormat, fetchInterval: Int?, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, @@ -650,6 +655,7 @@ fun MangaScreenLargeImpl( sharedChapterItems( manga = state.manga, chapters = chapters, + dateRelativeTime = dateRelativeTime, dateFormat = dateFormat, chapterSwipeStartAction = chapterSwipeStartAction, chapterSwipeEndAction = chapterSwipeEndAction, @@ -711,6 +717,7 @@ private fun SharedMangaBottomActionMenu( private fun LazyListScope.sharedChapterItems( manga: Manga, chapters: List, + dateRelativeTime: Boolean, dateFormat: DateFormat, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, @@ -739,7 +746,11 @@ private fun LazyListScope.sharedChapterItems( date = chapterItem.chapter.dateUpload .takeIf { it > 0L } ?.let { - dateFormat.format(Date(it)) + Date(it).toRelativeString( + context, + dateRelativeTime, + dateFormat, + ) }, readProgress = chapterItem.chapter.lastPageRead .takeIf { !chapterItem.chapter.read && it > 0L } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt index d98198155..4540aee95 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt @@ -123,6 +123,11 @@ object SettingsAppearanceScreen : SearchableSettings { var currentLanguage by remember { mutableStateOf(AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "") } val now = remember { Date().time } + val dateFormat by uiPreferences.dateFormat().collectAsState() + val formattedNow = remember(dateFormat) { + UiPreferences.dateFormat(dateFormat).format(now) + } + LaunchedEffect(currentLanguage) { val locale = if (currentLanguage.isEmpty()) { LocaleListCompat.getEmptyLocaleList() @@ -162,6 +167,15 @@ object SettingsAppearanceScreen : SearchableSettings { "${it.ifEmpty { stringResource(R.string.label_default) }} ($formattedDate)" }, ), + Preference.PreferenceItem.SwitchPreference( + pref = uiPreferences.relativeTime(), + title = stringResource(R.string.pref_relative_format), + subtitle = stringResource( + R.string.pref_relative_format_summary, + stringResource(R.string.relative_time_today), + formattedNow, + ), + ), ), ) } diff --git a/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt b/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt index 1f4a56d5f..1572faff4 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt @@ -43,6 +43,7 @@ fun UpdateScreen( state: UpdatesScreenModel.State, snackbarHostState: SnackbarHostState, lastUpdated: Long, + relativeTime: Boolean, onClickCover: (UpdatesItem) -> Unit, onSelectAll: (Boolean) -> Unit, onInvertSelection: () -> Unit, @@ -113,7 +114,7 @@ fun UpdateScreen( } updatesUiItems( - uiModels = state.getUiModel(context), + uiModels = state.getUiModel(context, relativeTime), selectionMode = state.selectionMode, onUpdateSelected = onUpdateSelected, onClickCover = onClickCover, diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index 75edfdd46..3c15c913d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -375,6 +375,12 @@ object Migrations { pref.getAndSet { it - "battery_not_low" } } } + if (oldVersion < 106) { + val pref = preferenceStore.getInt("relative_time", 7) + if (pref.get() == 0) { + uiPreferences.relativeTime().set(false) + } + } return true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt index 8f56c4fcb..39595fbe5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt @@ -99,6 +99,7 @@ class MangaScreen( MangaScreen( state = successState, snackbarHostState = screenModel.snackbarHostState, + dateRelativeTime = screenModel.relativeTime, dateFormat = screenModel.dateFormat, fetchInterval = successState.manga.fetchInterval, isTabletUi = isTabletUi(), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index 71b7c4bf7..0827caded 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -125,6 +125,7 @@ class MangaScreenModel( val chapterSwipeStartAction = libraryPreferences.swipeToEndAction().get() val chapterSwipeEndAction = libraryPreferences.swipeToStartAction().get() + val relativeTime by uiPreferences.relativeTime().asState(coroutineScope) val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get())) private val skipFiltered by readerPreferences.skipFiltered().asState(coroutineScope) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt index 6e0c1c474..62ac21cc1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt @@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.util.lang.toDateKey +import eu.kanade.tachiyomi.util.lang.toRelativeString import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -58,12 +59,14 @@ class UpdatesScreenModel( private val getChapter: GetChapter = Injekt.get(), private val libraryPreferences: LibraryPreferences = Injekt.get(), val snackbarHostState: SnackbarHostState = SnackbarHostState(), + uiPreferences: UiPreferences = Injekt.get(), ) : StateScreenModel(State()) { private val _events: Channel = Channel(Int.MAX_VALUE) val events: Flow = _events.receiveAsFlow() val lastUpdated by libraryPreferences.lastUpdatedTimestamp().asState(coroutineScope) + val relativeTime by uiPreferences.relativeTime().asState(coroutineScope) // First and last selected index in list private val selectedPositions: Array = arrayOf(-1, -1) @@ -373,7 +376,7 @@ class UpdatesScreenModel( val selected = items.filter { it.selected } val selectionMode = selected.isNotEmpty() - fun getUiModel(context: Context): List { + fun getUiModel(context: Context, relativeTime: Boolean): List { val dateFormat by mutableStateOf(UiPreferences.dateFormat(Injekt.get().dateFormat().get())) return items @@ -383,7 +386,11 @@ class UpdatesScreenModel( val afterDate = after?.item?.update?.dateFetch?.toDateKey() ?: Date(0) when { beforeDate.time != afterDate.time && afterDate.time != 0L -> { - val text = dateFormat.format(afterDate) + val text = afterDate.toRelativeString( + context = context, + relative = relativeTime, + dateFormat = dateFormat, + ) UpdatesUiModel.Header(text) } // Return null to avoid adding a separator between two items. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt index cf33f69c4..78a44dd23 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt @@ -57,6 +57,7 @@ object UpdatesTab : Tab { state = state, snackbarHostState = screenModel.snackbarHostState, lastUpdated = screenModel.lastUpdated, + relativeTime = screenModel.relativeTime, onClickCover = { item -> navigator.push(MangaScreen(item.update.mangaId)) }, onSelectAll = screenModel::toggleAllSelection, onInvertSelection = screenModel::invertSelection, diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt index 88477e8d5..e2f683685 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt @@ -1,5 +1,7 @@ package eu.kanade.tachiyomi.util.lang +import android.content.Context +import eu.kanade.tachiyomi.R import java.text.DateFormat import java.time.Instant import java.time.LocalDateTime @@ -42,3 +44,41 @@ fun Long.toDateKey(): Date { cal[Calendar.MILLISECOND] = 0 return cal.time } + +private const val MILLISECONDS_IN_DAY = 86_400_000L + +fun Date.toRelativeString( + context: Context, + relative: Boolean = true, + dateFormat: DateFormat = DateFormat.getDateInstance(DateFormat.SHORT), +): String { + if (!relative) { + return dateFormat.format(this) + } + val now = Date() + val difference = now.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY) - this.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY) + val days = difference.floorDiv(MILLISECONDS_IN_DAY).toInt() + return when { + difference < 0 -> dateFormat.format(this) + difference < MILLISECONDS_IN_DAY -> context.getString(R.string.relative_time_today) + difference < MILLISECONDS_IN_DAY.times(7) -> context.resources.getQuantityString( + R.plurals.relative_time, + days, + days, + ) + else -> dateFormat.format(this) + } +} + +private val Date.timeWithOffset: Long + get() { + return Calendar.getInstance().run { + time = this@timeWithOffset + val dstOffset = get(Calendar.DST_OFFSET) + this@timeWithOffset.time + timeZone.rawOffset + dstOffset + } + } + +fun Long.floorNearest(to: Long): Long { + return this.floorDiv(to) * to +} diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 67f33acca..bed8f0836 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -201,6 +201,9 @@ Yotsuba Tidal Wave Pure black dark mode + Relative timestamps + + \"%1$s\" instead of \"%2$s\" Date format Manage notifications @@ -223,6 +226,12 @@ Show in sources and extensions lists This does not prevent unofficial or potentially incorrectly flagged extensions from surfacing NSFW (18+) content within the app. + Today + + Yesterday + %1$d days ago + + Display Grid size diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt index eea05b4ca..6720e74c5 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt @@ -70,7 +70,6 @@ fun AdaptiveSheet( val alpha by animateFloatAsState( targetValue = targetAlpha, animationSpec = sheetAnimationSpec, - label = "alpha", ) val internalOnDismissRequest: () -> Unit = { scope.launch { From 4e69bf993a7addb93a0987ae0e037f1e1f7e127a Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sun, 24 Sep 2023 23:22:45 +0200 Subject: [PATCH 35/59] Translations update from Hosted Weblate (#9919) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Weblate translations Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ar/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cs/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/it/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ja/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ko/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nb_NO/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ne/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/th/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/ Translation: Tachiyomi/Tachiyomi 0.x Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> Co-authored-by: Ali Aljishi Co-authored-by: C201 Co-authored-by: Dan Co-authored-by: Dexroneum Co-authored-by: Eduard Ereza Martínez Co-authored-by: FateXBlood Co-authored-by: Giorgio Sanna Co-authored-by: ID-86 Co-authored-by: InfinityDouki56 Co-authored-by: Lyfja Co-authored-by: Milo Ivir Co-authored-by: Paavalen Lingachetti Co-authored-by: Pitpe11 Co-authored-by: Shjosan Co-authored-by: Uzuki Shimamura Co-authored-by: Vetle Ledaal Co-authored-by: abc0922001 Co-authored-by: altinat Co-authored-by: orkan gökçe alaz aşina Co-authored-by: sarami --- i18n/src/main/res/values-ar/strings.xml | 16 ++--- i18n/src/main/res/values-b+es+419/strings.xml | 6 -- i18n/src/main/res/values-be/strings.xml | 7 --- i18n/src/main/res/values-bg/strings.xml | 5 -- i18n/src/main/res/values-bn/strings.xml | 5 -- i18n/src/main/res/values-ca/strings.xml | 10 +--- i18n/src/main/res/values-ceb/strings.xml | 5 -- i18n/src/main/res/values-cs/strings.xml | 11 +--- i18n/src/main/res/values-cv/strings.xml | 10 ++-- i18n/src/main/res/values-da/strings.xml | 5 -- i18n/src/main/res/values-de/strings.xml | 10 +--- i18n/src/main/res/values-el/strings.xml | 12 ++-- i18n/src/main/res/values-eo/strings.xml | 5 -- i18n/src/main/res/values-es/strings.xml | 6 -- i18n/src/main/res/values-eu/strings.xml | 5 -- i18n/src/main/res/values-fa/strings.xml | 5 -- i18n/src/main/res/values-fi/strings.xml | 5 -- i18n/src/main/res/values-fil/strings.xml | 6 +- i18n/src/main/res/values-fr/strings.xml | 19 +++--- i18n/src/main/res/values-gl/strings.xml | 5 -- i18n/src/main/res/values-he/strings.xml | 7 --- i18n/src/main/res/values-hi/strings.xml | 5 -- i18n/src/main/res/values-hr/strings.xml | 11 +--- i18n/src/main/res/values-hu/strings.xml | 5 -- i18n/src/main/res/values-in/strings.xml | 4 -- i18n/src/main/res/values-it/strings.xml | 11 +--- i18n/src/main/res/values-ja/strings.xml | 9 +-- i18n/src/main/res/values-jv/strings.xml | 4 -- i18n/src/main/res/values-kk/strings.xml | 5 -- i18n/src/main/res/values-km/strings.xml | 4 -- i18n/src/main/res/values-ko/strings.xml | 58 +++++++++++-------- i18n/src/main/res/values-lt/strings.xml | 6 -- i18n/src/main/res/values-lv/strings.xml | 6 -- i18n/src/main/res/values-ms/strings.xml | 4 -- i18n/src/main/res/values-nb-rNO/strings.xml | 22 +++---- i18n/src/main/res/values-ne/strings.xml | 27 ++++----- i18n/src/main/res/values-nl/strings.xml | 13 ++--- i18n/src/main/res/values-nn/strings.xml | 5 -- i18n/src/main/res/values-pl/strings.xml | 7 --- i18n/src/main/res/values-pt-rBR/strings.xml | 10 +--- i18n/src/main/res/values-pt/strings.xml | 6 -- i18n/src/main/res/values-ro/strings.xml | 6 -- i18n/src/main/res/values-ru/strings.xml | 8 +-- i18n/src/main/res/values-sa/strings.xml | 5 -- i18n/src/main/res/values-sc/strings.xml | 5 -- i18n/src/main/res/values-sdh/strings.xml | 5 -- i18n/src/main/res/values-sk/strings.xml | 6 -- i18n/src/main/res/values-sq/strings.xml | 5 -- i18n/src/main/res/values-sr/strings.xml | 6 -- i18n/src/main/res/values-sv/strings.xml | 10 +--- i18n/src/main/res/values-th/strings.xml | 9 +-- i18n/src/main/res/values-tr/strings.xml | 12 ++-- i18n/src/main/res/values-uk/strings.xml | 22 ++++--- i18n/src/main/res/values-uz/strings.xml | 5 -- i18n/src/main/res/values-vi/strings.xml | 4 -- i18n/src/main/res/values-zh-rCN/strings.xml | 4 -- i18n/src/main/res/values-zh-rTW/strings.xml | 5 +- 57 files changed, 125 insertions(+), 379 deletions(-) diff --git a/i18n/src/main/res/values-ar/strings.xml b/i18n/src/main/res/values-ar/strings.xml index b6a544028..718a2c18c 100644 --- a/i18n/src/main/res/values-ar/strings.xml +++ b/i18n/src/main/res/values-ar/strings.xml @@ -112,7 +112,7 @@ اليسار اليمين المركز - نوع التدوير الافتراضي + التدوير الافتراضي حر الوضع الرأسي اﻹجباري الوضع الأفقي الإجباري @@ -567,7 +567,7 @@ تاريخ الرفع افقي رأسي - نوع التدوير + التدوير تلقائيًّا إنشاء مجلدات وفقا لعنوان الإدخالات حفظ الصفحات في مجلدات منفصلة @@ -624,18 +624,9 @@ قد لا يعمل النسخ الاحتياطيُّ أو الاستعادة إن عطِّلت أمثَلَة MIUI. الخدمات التي تقدم ميزات محسنة لأجل مصادر معينه. الإدخالات سوف يتم تتبعها عندما يتم إضافتها الي المكتبة. خدمات محسَّنة - اليوم المصادقة لتأكيد التغيير الافتراضي الأنشطة التي تعمل في الخلفية - - الأمس - منذ %1$d أيام - منذ %1$d أيام - منذ %1$d أيام - منذ %1$d أيام - منذ %1$d أيام - تتبع معكوس ازرق مخضر و فيروز @@ -643,7 +634,7 @@ دليل البدء ساعد بالترجمة واجهة مستخدم الجهاز اللوحي - فئات المستثناة + الفئات المستثناة المثبت إجمالي الإدخالات تحذير @@ -881,4 +872,5 @@ خطأ HTTP %d، انظر في WebView لم نصل %s افتح %s + انقل السلسلة للقعر \ No newline at end of file diff --git a/i18n/src/main/res/values-b+es+419/strings.xml b/i18n/src/main/res/values-b+es+419/strings.xml index ede476a22..743721c47 100644 --- a/i18n/src/main/res/values-b+es+419/strings.xml +++ b/i18n/src/main/res/values-b+es+419/strings.xml @@ -591,12 +591,6 @@ Actualizar rastreadores cuando se actualice la biblioteca Actualizar rastreadores automáticamente Restricciones: %s - - Ayer - Hace %1$d dias - Hace %1$d dias - - Hoy Modo oscuro con negro puro Tema Yotsuba Yin y Yang diff --git a/i18n/src/main/res/values-be/strings.xml b/i18n/src/main/res/values-be/strings.xml index 1cefa0e7b..f25eec920 100644 --- a/i18n/src/main/res/values-be/strings.xml +++ b/i18n/src/main/res/values-be/strings.xml @@ -278,13 +278,6 @@ Змясціць у экран Маштабаванне Колеры наадварот - - Учора - %1$d дні таму - %1$d дзён таму - %1$d дзён таму - - Сёння Бірузовы Знешнасць Аўтэнтыфікацыя для пацверджання змяненняў diff --git a/i18n/src/main/res/values-bg/strings.xml b/i18n/src/main/res/values-bg/strings.xml index 097115845..0c0c7fdd0 100644 --- a/i18n/src/main/res/values-bg/strings.xml +++ b/i18n/src/main/res/values-bg/strings.xml @@ -557,10 +557,6 @@ Чувствителност за скриване на менюто при превъртане Най-висока Непрочетена - - Вчера - Преди %1$d дни - Корица Предупреждение Удостоверете, за да потвърдите промяната @@ -625,7 +621,6 @@ Следваща страница Език Показвай в списъка с източници и разширения - Днес Информация Покажи зони за натискане, когато четецът се отвори Обърни позициите на разделените широки страници diff --git a/i18n/src/main/res/values-bn/strings.xml b/i18n/src/main/res/values-bn/strings.xml index 7f3dc3ef9..04ddd3487 100644 --- a/i18n/src/main/res/values-bn/strings.xml +++ b/i18n/src/main/res/values-bn/strings.xml @@ -566,11 +566,6 @@ লাইব্রেরি আপডেট করার সময় ট্র্যাকার আপডেট করুন স্বয়ংক্রিয়ভাবে রিফ্রেশ ট্র্যাকার বিধিনিষেধ: %s - - গতকাল - %1$d দিন আগে - - সম্প্রতি বিশুদ্ধ কালো অন্ধকার মোড চার পাতা ইয়িন এবং ইয়াং diff --git a/i18n/src/main/res/values-ca/strings.xml b/i18n/src/main/res/values-ca/strings.xml index 033783918..cf45eaeb6 100644 --- a/i18n/src/main/res/values-ca/strings.xml +++ b/i18n/src/main/res/values-ca/strings.xml @@ -136,7 +136,7 @@ Sense animació Normal Ràpida - Tipus de rotació per defecte + Rotació per defecte Lliure Vertical forçada Horitzontal forçada @@ -525,7 +525,7 @@ Baixada automàtica Horitzontal Vertical - Tipus de rotació + Rotació Dreta Esquerra Següent @@ -567,11 +567,6 @@ Encara no teniu cap categoria. S’està actualitzant la biblioteca… (%1$d/%2$d) Serveis millorats - - Ahir - Fa %1$d dies - - Avui Per defecte Advertència Autentiqueu-vos per a confirmar el canvi @@ -817,4 +812,5 @@ No hi ha connexió a Internet HTTP %d, comproveu el lloc web en una WebView No s’ha pogut accedir a %s + Mou la sèrie a baix de tot \ No newline at end of file diff --git a/i18n/src/main/res/values-ceb/strings.xml b/i18n/src/main/res/values-ceb/strings.xml index 81529b94c..cf1808fb3 100644 --- a/i18n/src/main/res/values-ceb/strings.xml +++ b/i18n/src/main/res/values-ceb/strings.xml @@ -135,7 +135,6 @@ Tagoa ang sulod sa pahibalo Lig-on nga screen NSFW (18+) Mga Tinubdan - Karon Pagpakita Mga butang kada laray Hulagway @@ -158,10 +157,6 @@ Human sa %1$s ka minuto Human sa %1$s ka minuto - - Kagahapon - %1$d ka adlaw ang milabay - Nagpaubos Pinaagi sa petsa sa pag-upload Pinaagi sa numero sa kapitulo diff --git a/i18n/src/main/res/values-cs/strings.xml b/i18n/src/main/res/values-cs/strings.xml index 49b800e0f..123bffa35 100644 --- a/i18n/src/main/res/values-cs/strings.xml +++ b/i18n/src/main/res/values-cs/strings.xml @@ -76,7 +76,7 @@ Černá Stránkované (zleva doprava) Stránkované (zprava doleva) - Výchozí typ otáčení + Výchozí otáčení Volné Zamknuto na výšku Zamknuto na šířku @@ -538,7 +538,7 @@ Datum načtení kapitoly Na šířku Na výšku - Typ otočení + Otáčení Vytváří složky podle názvu položky Uložit stránky do samostatných složek Akce @@ -593,12 +593,6 @@ Příručka Začínáme Uživatelské rozhraní tabletu Sledovat - - Včera - Před %1$d dny - Před %1$d dny - - Dnes Modrozelená a Tyrkysová Vzhled Potvrďte změnu ověřením @@ -833,4 +827,5 @@ Nelze dosáhnout %s HTTP %d, zkontrolovat web v WebView Odemknout %s + Přesunout sérii na konec \ No newline at end of file diff --git a/i18n/src/main/res/values-cv/strings.xml b/i18n/src/main/res/values-cv/strings.xml index 4e43a567a..17d50a35d 100644 --- a/i18n/src/main/res/values-cv/strings.xml +++ b/i18n/src/main/res/values-cv/strings.xml @@ -252,7 +252,7 @@ Ҫак хушмана урӑх кӗме май ҫук. Вӑл тӗрӗс мар ӗҫлеме тата апа йӑнӑшлаттарма пултарать. Ӑна катертме сӗнетпӗр. Ку хушмана шанчӑклӑ мар ӗнентерӳ хучӗпе алӑ пуснӑ тата ӑна пуҫарман. \n -\nСийенлӗ хушма Tachiyomi-ри упранакан кирек мӗнле шут пӗлӗмӗсене шута илме йе хӑй ирӗклӗ йума пурнӑҫлама пултарать. +\nСийенлӗ хушма упранакан кирек мӗнле шут пӗлӗмӗсене шута илме йе хӑй ирӗклӗ йума пурнӑҫлама пултарать. \n \nҪак ӗнентерӳ хутне шаннипе есӗ ҫав теветкеле йышӑнатӑн. @@ -571,17 +571,12 @@ Тийесе илнӗ Шыв хӑпарнин хумӗ Ап темми - Пайан Лавантӑ Ин тата Йан Ҫӑл куҫсем, хушмасем, пӗтӗмӗшле шырав Симӗс пан улми Йутсупа Серилӗхсене ҫӗнетнине сиктер - - Ӗнер - %1$d кун кайалла - Чараксӑр тетел урлӑ ҫеҫ Серилӗхе пуҫламан Такку @@ -635,4 +630,7 @@ Малтанхилле Shizuku-н хушма ларткӑча усӑ курма Shizuku ларт тата ҫут. Йурӗ + %s уҫ + Серилӗхе вӗҫе куҫар + Кӗртнӗ пухмӑшсенче пулнӑ пулсан та кӑларса пӑрахнӑ пухмӑшсенче пулнӑ серилӗхсем ҫӗнелмӗҫ. \ No newline at end of file diff --git a/i18n/src/main/res/values-da/strings.xml b/i18n/src/main/res/values-da/strings.xml index ccd1e3144..e0a8ea4a0 100644 --- a/i18n/src/main/res/values-da/strings.xml +++ b/i18n/src/main/res/values-da/strings.xml @@ -144,14 +144,9 @@ Håndter notifikationer Sikkerhed Kræv oplåsning - - I går - %1$d dage siden - NSFW (18+) kilder Vis i kilder og udvidelsesliste Dette forhindrer ikke uofficielle eller potentielt ukorrekt markerede udvidelser fra at vise NSFW (18+) indhold i appen. - I dag Efter %1$s minut Efter %1$s minutter diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml index 44b84fdc5..975834b86 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -110,7 +110,7 @@ Links Rechts Mitte - Standard-Ausrichtungstyp + Standardausrichtung Frei Hochformat erzwingen Querformat erzwingen @@ -534,7 +534,7 @@ Hochformat Erstellt Ordner nach dem Titel der Einträge Speichere Seiten in separate Ordner - Ausrichtungstyp + Ausrichtung Aktionen Graustufen Inkognito-Modus deaktivieren @@ -582,11 +582,6 @@ Höchste Empfindlichkeit für das Menü-Ausblenden beim Scrollen Invertiert - - Gestern - Vor %1$d Tagen - - Heute Blaugrün & Türkis Erscheinungsbild Authentifiziere dich, um die Änderungen zu bestätigen @@ -817,4 +812,5 @@ Keine Internetverbindung %s konnte nicht erreicht werden %s entsperren + Serie nach unten verschieben \ No newline at end of file diff --git a/i18n/src/main/res/values-el/strings.xml b/i18n/src/main/res/values-el/strings.xml index 5a8f8939c..ad05d0eb1 100644 --- a/i18n/src/main/res/values-el/strings.xml +++ b/i18n/src/main/res/values-el/strings.xml @@ -137,7 +137,7 @@ Χωρίς κίνηση Κανονική Γρήγορη - Προεπιλεγμένος τύπος περιστροφής + Προεπιλεγμένη περιστροφή Ελεύθερο Κλειδωμένο κατακόρυφα Κλειδωμένο οριζόντια @@ -535,7 +535,7 @@ Δημιουργεί φακέλους σύμφωνα με τον τίτλο των καταχωρήσεων Αποθήκευση σελίδων σε ξεχωριστούς φακέλους Ενέργειες - Τύπος περιστροφής + Περιστροφή Κλίμακα του γκρι Απενεργοποίηση λειτουργίας ανώνυμης περιήγησης Αυτόματο @@ -581,12 +581,7 @@ Ύψιστη Υψηλή Ευαισθησία για την απόκρυψη του μενού κατά την κύλιση - - Εχθές - %1$d μέρες πριν - Αντεστραμμένο - Σήμερα Teal & Τιρκουάζ Έλεγχος ταυτότητας για επιβεβαίωση αλλαγής Προεπιλογή @@ -640,7 +635,7 @@ Παραλήφθηκαν %1$d ενημέρωση(εις) παραλείφθηκε(-αν) Αντίστροφο πορτρέτο - Μετακίνηση σειράς στην κορυφή + Μετακίνηση σειράς προς τα πάνω Απενεργοποιημένο Μια νέα έκδοση είναι διαθέσιμη από τις επίσημες κυκλοφορίες. Πατήστε για να μάθετε πώς να μεταβείτε από ανεπίσημες κυκλοφορίες του F-Droid. Σφάλμα κατά την αποθήκευση της εικόνας @@ -817,4 +812,5 @@ HTTP %d, ελέγξτε την ιστοσελίδα στο WebView Δεν υπάρχει σύνδεση στο διαδίκτυο Ξεκλείδωμα %s + Μετακίνηση σειράς προς τα κάτω \ No newline at end of file diff --git a/i18n/src/main/res/values-eo/strings.xml b/i18n/src/main/res/values-eo/strings.xml index 857703896..074e16dd3 100644 --- a/i18n/src/main/res/values-eo/strings.xml +++ b/i18n/src/main/res/values-eo/strings.xml @@ -384,11 +384,6 @@ Malŝaltita Ŝaltita Elementoj vice - - Hieraŭ - Antaŭ %1$d tagoj - - Hodiaŭ Jino kaj Jango Verda pomo Apa etoso diff --git a/i18n/src/main/res/values-es/strings.xml b/i18n/src/main/res/values-es/strings.xml index eda92c287..4fea20f46 100644 --- a/i18n/src/main/res/values-es/strings.xml +++ b/i18n/src/main/res/values-es/strings.xml @@ -627,12 +627,6 @@ Más alta Sensibilidad para ocultar automáticamente el menú al desplazarse Invertido - - Ayer - Hace %1$d días - Hace %1$d días - - Hoy Azul marino y turquesa Apariencia Identifícate para confirmar el cambio diff --git a/i18n/src/main/res/values-eu/strings.xml b/i18n/src/main/res/values-eu/strings.xml index 77162b700..021838996 100644 --- a/i18n/src/main/res/values-eu/strings.xml +++ b/i18n/src/main/res/values-eu/strings.xml @@ -193,10 +193,6 @@ Ez dago aurreko kapitulurik Kopiatu Android bertsio hau jada ez da onartzen - - Atzo - Duela %1$d egun - Zaharkitua Desinstalatu Erakutsi orrialdearen zenbakia @@ -435,7 +431,6 @@ NSFW (18+) iturriak Erakutsi iturrien eta luzapenen zerrendetan Honek ez du eragozten ofizialak ez diren edo oker markatutako luzapenek NSFW (18+) edukia aplikazioan erakustea. - Gaur Bistaratu Errenkada bakoitzeko elementu kopurua Eguneraketa globalak diff --git a/i18n/src/main/res/values-fa/strings.xml b/i18n/src/main/res/values-fa/strings.xml index cb38c0439..47968fd1c 100644 --- a/i18n/src/main/res/values-fa/strings.xml +++ b/i18n/src/main/res/values-fa/strings.xml @@ -550,14 +550,9 @@ فقط روی شبکه‌ی نامحدود که شروع نشده‌اند محدودیت‌ها: %s - - دیروز - %1$d روز پیش - با قسمت‌(های) خوانده‌نشده ردیاب‌ها را به طور خودکار تازه کن از به‌روزرسانی ورودی‌ها صرف‌نظر کنید - امروز هر 3 روز فقط روی Wi-Fi به‌روزرسانی ردیاب‌ها هنگام به‌روزرسانی کتابخانه diff --git a/i18n/src/main/res/values-fi/strings.xml b/i18n/src/main/res/values-fi/strings.xml index c97467e5f..bcb3a865a 100644 --- a/i18n/src/main/res/values-fi/strings.xml +++ b/i18n/src/main/res/values-fi/strings.xml @@ -552,10 +552,6 @@ Aloitusopas Varoitus: massalataukset voivat johtaa siihen, että lähteet muuttuvat hitaammiksi käyttää ja/tai ne estävät Tachiyomin käytön. Napauta saadaksesi lisätietoja. Päivitä seurantapalvelimet kirjaston päivityksen yhteydessä - - Eilen - %1$d päivää sitten - Näytä manga Kansikuva ruudukko Dynaaminen @@ -573,7 +569,6 @@ Yotsuba Täysin musta pimeätila Ei lukemattomia lukuja - Tänään Sarjalla on lukemattomia kappaleita Sovelluksen teema Varoitus diff --git a/i18n/src/main/res/values-fil/strings.xml b/i18n/src/main/res/values-fil/strings.xml index e1292a666..db931e8d3 100644 --- a/i18n/src/main/res/values-fil/strings.xml +++ b/i18n/src/main/res/values-fil/strings.xml @@ -582,11 +582,6 @@ Pinakamataas Sensitivity para sa pagtatago ng menu sa scroll Baligtad - - Kahapon - %1$d araw na ang makalipas - - Ngayon Teal at Turquoise Hitsura Patotohanan para makumpirma ang pagbabago @@ -817,4 +812,5 @@ Walang koneksyon sa Internet HTTP %d, tignan ang website sa WebView Hindi maabot ang %s + Ilagay sa ibaba ang serye \ No newline at end of file diff --git a/i18n/src/main/res/values-fr/strings.xml b/i18n/src/main/res/values-fr/strings.xml index 6f1d9e714..185b1130b 100644 --- a/i18n/src/main/res/values-fr/strings.xml +++ b/i18n/src/main/res/values-fr/strings.xml @@ -104,7 +104,7 @@ Gauche Droite Centre - Type de rotation par défaut + Rotation par défaut Libre Bloqué sur portrait Bloqué sur paysage @@ -589,7 +589,7 @@ Trier par Format de chapitre invalide Chapitre non trouvé - Mode de rotation + Rotation Auto Mettre à jour les services de suivi lors de la mise à jour de la bibliothèque Actualiser automatiquement les services de suivi @@ -627,12 +627,6 @@ Maximale Sensibilité pour masquer le menu lors du défilement Inversé - - Hier - Il y a %1$d jours - Il y a %1$d jours - - Aujourd\'hui Bleu canard et turquoise Authentifiez-vous pour confirmer les changements Apparence @@ -750,7 +744,7 @@ Vous êtes sur le point de retirer « %s » de votre bibliothèque Autorisations de stockage non accordées Recherche… - Passées car la série ne nécessite pas de mise à jour + Ignorée car la série ne nécessite pas de mises à jour Oups ! Thème, format de la date et de l\'heure Téléchargement automatique, téléchargement anticipé @@ -844,7 +838,7 @@ Appuyez ici pour de l\'aide sur Cloudflare Débloquer %s Synchronisation de la bibliothèque - Intervals + Intervalles Synchronisation de la bibliothèque complété Licenciés - Aucun chapitres à montrer Aucune connexion internet @@ -858,4 +852,9 @@ %d jours %d jours + Configurer pour mettre à jour tous les + Personnaliser l\'intervalle + Déplacer la série vers le bas + Supprimez également de %s + Impossible de joindre %s \ No newline at end of file diff --git a/i18n/src/main/res/values-gl/strings.xml b/i18n/src/main/res/values-gl/strings.xml index 1b58a9ac9..7227d6898 100644 --- a/i18n/src/main/res/values-gl/strings.xml +++ b/i18n/src/main/res/values-gl/strings.xml @@ -261,7 +261,6 @@ Fontes, extensións, procura global Baixar os rexistros de erros, optimizacións de batería Maremoto - Hoxe Con capítulos sin ler Os elementos das categorías excluídas non se actualizarán aínda se están tamén nas categorías incluídas. Versión @@ -509,10 +508,6 @@ Cancelar todo para esta serie Por data de subida Preme para ver os detalles do erro - - Onte - Fai %1$d días - Omitir actualizacións Restricións: %s Opcións de ordenación e visualización por categoría diff --git a/i18n/src/main/res/values-he/strings.xml b/i18n/src/main/res/values-he/strings.xml index d419e9157..6e71fa14f 100644 --- a/i18n/src/main/res/values-he/strings.xml +++ b/i18n/src/main/res/values-he/strings.xml @@ -379,7 +379,6 @@ מקורות NSFW (18+) הצג ברשימות מקורות ותוספים זה לא מונע תוספים לא רשמיים או תוספים שעלולים לסמן באופן שגוי מלהציג תוכן NSFW (18+) בתוך האפליקציה. - היום תצוגה עדכן עוקבים בעת עדכון הספרייה אפשר הכל @@ -428,12 +427,6 @@ דלג על עדכוני פריטים נכשל בקבלת רשימת ההרחבות שו\"ת ומדריכים - - אתמול - לפני יומיים - לפני %1$d ימים - לפני %1$d ימים - 18+ אין כל 3 ימים diff --git a/i18n/src/main/res/values-hi/strings.xml b/i18n/src/main/res/values-hi/strings.xml index d4cff453b..c5f8d458f 100644 --- a/i18n/src/main/res/values-hi/strings.xml +++ b/i18n/src/main/res/values-hi/strings.xml @@ -559,7 +559,6 @@ परिदृश्य कुल आइटम मिडनाइट डस्क - आज पुस्तकालय अपडेट करते समय ट्रैकर्स को अपडेट करें शामिल करें: %s ऐप की जानकारी @@ -572,10 +571,6 @@ MIUI ऑप्टिमाइज़ेशन अक्षम होने पर बैकअप/पुनर्स्थापना ठीक से काम नहीं कर सकता है। पृष्ठभूमि गतिविधि कुछ निर्माताओं के पास अतिरिक्त ऐप प्रतिबंध हैं जो पृष्ठभूमि सेवाओं को मारते हैं। इस वेबसाइट में इसे ठीक करने के बारे में अधिक जानकारी है। - - कल - %1$d दिन पहले - अमान्य अध्याय प्रारूप के अनुसार ऑर्डर करें क्लिपबोर्ड पर कॉपी करने में विफल diff --git a/i18n/src/main/res/values-hr/strings.xml b/i18n/src/main/res/values-hr/strings.xml index 227cdcc33..13ebd5f37 100644 --- a/i18n/src/main/res/values-hr/strings.xml +++ b/i18n/src/main/res/values-hr/strings.xml @@ -279,7 +279,7 @@ Trenutačno: Završeno: Modus čitanja - Za ovaj serijal + Za ovu seriju Ovu sliku koristiti kao naslovnicu\? Nije bilo moguće učitati sliku Sljedeće poglavlje nije pronađeno @@ -581,12 +581,6 @@ Yotsuba Jin i Jang Invertirano - - Prije %1$d dan - Prije %1$d dana - Prije %1$d dana - - Danas Potpuno crna tamna tema Strawberry Daiquiri Izgled @@ -652,7 +646,7 @@ Preskočeno Preskočena aktualiziranja: %1$d Preokrenuto uspravno - Pomakni serijal na vrh + Pomakni seriju na vrh Deaktivirano Nema unosa u biblioteci za spremanje u sigurnosnu kopiju Poboljšava performanse čitača @@ -833,4 +827,5 @@ Ne postoji veza s internetom HTTP %d, provjeri web stranicu u WebView Nije bilo moguće povezati se s računalom %s + Pomakni seriju na kraj \ No newline at end of file diff --git a/i18n/src/main/res/values-hu/strings.xml b/i18n/src/main/res/values-hu/strings.xml index 9df1cbc82..3d13e90e4 100644 --- a/i18n/src/main/res/values-hu/strings.xml +++ b/i18n/src/main/res/values-hu/strings.xml @@ -338,11 +338,6 @@ Követők automatikus frissítése Polip Eper koktél - - Tegnap - %1$d napja - - Ma Teljesen fekete sötét mód Yotsuba Jin és Jang diff --git a/i18n/src/main/res/values-in/strings.xml b/i18n/src/main/res/values-in/strings.xml index 1f4824c66..3f5560f05 100644 --- a/i18n/src/main/res/values-in/strings.xml +++ b/i18n/src/main/res/values-in/strings.xml @@ -569,10 +569,6 @@ Tinggi Tertinggi Terbalik - - %1$d hari yang lalu - - Hari Ini Panduan awal mulai Lacak Teal & Pirus diff --git a/i18n/src/main/res/values-it/strings.xml b/i18n/src/main/res/values-it/strings.xml index 76403f394..5204cadce 100644 --- a/i18n/src/main/res/values-it/strings.xml +++ b/i18n/src/main/res/values-it/strings.xml @@ -101,7 +101,7 @@ Sinistra Destra Centro - Orientamento predefinito + Rotazione predefinita Libero Bloccato verticale Bloccato orizzontale @@ -574,7 +574,7 @@ Tocca per vedere i dettagli Questa versione di Android non è più supportata Impossibile copiare negli appunti - Orientamento + Rotazione Disabilita modalità incognito Orizzontale Verticale @@ -613,12 +613,6 @@ Più alto Sensibilità per nascondere il menù allo scorrimento Inversa - - Ieri - %1$d giorni fa - %1$d giorni fa - - Oggi Modalità scura con nero puro Yotsuba Yin e Yang @@ -866,4 +860,5 @@ Nessuna connessione ad internet %s non raggiungibile Sblocca %s + Spostare la serie in fondo \ No newline at end of file diff --git a/i18n/src/main/res/values-ja/strings.xml b/i18n/src/main/res/values-ja/strings.xml index 6041abf98..ea2e5feb8 100644 --- a/i18n/src/main/res/values-ja/strings.xml +++ b/i18n/src/main/res/values-ja/strings.xml @@ -118,7 +118,7 @@ 中央 通常 速い - 既定の回転モード + 既定の画面向き 自動回転 縦向き画面を強制 R @@ -533,7 +533,7 @@ 章が見つかりませんでした シークレットモードを無効にする 追跡ガイド - 回転モード + 画面向き 自動 項目のタイトルに基づいてフォルダを作成 別々のフォルダにページを保存 @@ -568,10 +568,6 @@ 高い 最高 反転配色 - - %1$d日前 - - 今日 翻訳に協力 入門ガイド タブレットUI @@ -801,4 +797,5 @@ インターネット接続がありません %sにアクセスできませんでした %sをアンロック + シリーズを底に移動 \ No newline at end of file diff --git a/i18n/src/main/res/values-jv/strings.xml b/i18n/src/main/res/values-jv/strings.xml index 14b9636aa..23a7654f6 100644 --- a/i18n/src/main/res/values-jv/strings.xml +++ b/i18n/src/main/res/values-jv/strings.xml @@ -179,10 +179,6 @@ Ijo apel Takon jawab lan panduan Iki ora nyegah ekstensi kang ora resmi utawa salah dilabeli kanggo nampilake konten NSFW (18+) ing aplikasi. - Dinten puniki - - %1$d dinten kala-wingi - Mati Kaamanan Tansah diff --git a/i18n/src/main/res/values-kk/strings.xml b/i18n/src/main/res/values-kk/strings.xml index 58d841434..49a02af59 100644 --- a/i18n/src/main/res/values-kk/strings.xml +++ b/i18n/src/main/res/values-kk/strings.xml @@ -39,10 +39,6 @@ Бет (солдан оңға қарай) Санаттарыңыз жоқ. Жаңа санат жасау үшін және кітапханаңызды ұйымдастыру үшін қосу батырмасын басыңыз. Келесі - - Кеше - %1$d күн бұрын - Соңғы жаңартуды тексеру Оқылмаған тараулар Тізім @@ -71,7 +67,6 @@ Қызғылт пен жасыл Қап-қараңғы режим Инь мен Йянь - Бүгін Өшірулі Әр 6 сағат сайын Әр 12 сағат сайын diff --git a/i18n/src/main/res/values-km/strings.xml b/i18n/src/main/res/values-km/strings.xml index 85cbee0ce..626099715 100644 --- a/i18n/src/main/res/values-km/strings.xml +++ b/i18n/src/main/res/values-km/strings.xml @@ -141,10 +141,6 @@ ការពារអេក្រង់ ប្រភពមិនល្អ(១៨+) បង្ហាញនៅក្នុងបញ្ចីប្រភព - ថ្ងៃនេះ - - %1$d ថ្ងៃមុន - ការបង្ហាញ ធាតុក្នុងមួយជួ បញ្ឈរ diff --git a/i18n/src/main/res/values-ko/strings.xml b/i18n/src/main/res/values-ko/strings.xml index f6c3e5560..e9f912b87 100644 --- a/i18n/src/main/res/values-ko/strings.xml +++ b/i18n/src/main/res/values-ko/strings.xml @@ -66,8 +66,8 @@ 정보 격자 크기 데이터 이전 - 확장기능 - 확장기능 정보 + 확장 앱 + 확장 앱 정보 전체 검색 일시중지 세로 @@ -92,10 +92,10 @@ 신뢰 신뢰되지않음 삭제 - 신뢰할 수 없는 확장기능 - 이 확장기능은 신뢰할 수 없는 인증서로 서명되어 활성화되지 않았습니다. + 신뢰할 수 없는 확장 앱 + 이 확장앱은 신뢰할 수 없는 인증서로 서명되어 활성화되지 않았습니다. \n -\n일부 악의적인 확장기능은 Tachiyomi에 저장된 로그인 정보를 읽거나 임의의 코드를 실행할 수도 있습니다. +\n일부 악의적인 확장 앱은 Tachiyomi에 저장된 로그인 정보를 읽거나 임의의 코드를 실행할 수도 있습니다. \n \n이 인증서를 신뢰하면 이러한 위험에 노출될 수 있습니다. 전체화면 @@ -179,7 +179,7 @@ %1$s화 다운로드 중 (%1$d/%2$d) 오류 - 일시중지됨 + 일시정지 회차 번호 소스 기준 회차 번호 기준 @@ -387,9 +387,6 @@ 현재 만화에만 적용 읽기 모드 서재의 모든 항목에 적용됩니다 - - %1$d일 전 - 모서리 여백 앱 정보 초기 설정 도움말 @@ -415,7 +412,6 @@ 화면 보안 잠금 해제 필요 모양 - 오늘 전역 업데이트 보안 및 개인정보 보호 @@ -449,7 +445,7 @@ 디스플레이 필터링된 회차 건너뛰기 매우 높음 - 확장기능 업데이트 + 확장 앱 업데이트 기본값으로 설정 알림 설정 서재의 모든 항목에 적용 @@ -463,9 +459,9 @@ 회차 업데이트 포함: %s 백그라운드 활동 - 안 읽은 회차가 있을 때만 + 안 읽은 회차가 있음 카테고리 별 정렬 설정 - Shizuku를 확장기능 인스톨러로 사용하려면 Shizuku를 먼저 설치해 주세요. + Shizuku를 확장 앱 인스톨러로 사용하려면 Shizuku를 먼저 설치해 주세요. 전부 업데이트 백업에 항목이 포함되어 있지 않습니다. 개발자와 공유할 수 있는 오류 로그 파일을 생성합니다 @@ -515,21 +511,21 @@ 읽지 않은 만화를 건너 뛰었습니다 이 안드로이드 버전은 더이상 지원되지 않습니다 - %d개의 확장기능 업데이트가 있습니다 + %d개의 확장 앱 업데이트가 있습니다 Cloudflare를 통과하지 못했습니다 - Tachiyomi를 사용하려면 WebView가 필요합니다 + Tachiyomi 앱의 기능을 사용하려면 WebView가 필요합니다 호환성을 위해 WebView 어플리케이션을 업데이트 해 주세요 넓은 이미지 이동 이 확장 프로그램은 더 이상 사용할 수 없습니다. 제대로 작동하지 않을 수 있으며 앱에 문제가 발생할 수 있습니다. 제거하는 것이 좋습니다. - 확장기능 설치 중… + 확장 앱 설치 중… 레거시 트래킹 서재 표지 새로고침 오류 로그 공유 회차를 찾을 수 없습니다 결과가 없습니다 - 이 확장기능의 소스는 19금 콘텐츠가 포함될 수 있습니다 + 이 확장 앱의 소스는 성인 컨텐츠가 포함될 수 있습니다 트래커 사용 시작 지금 다운로드 시작 @@ -553,7 +549,7 @@ 지원 종료 검색 결과가 없습니다 넓은 페이지 분할 시 배치가 읽는 방향과 다를 경우 - 19금 + 성인 컨텐츠 카테고리 탭 보이기 챕터를 가져온 날짜순 전체 항목 개수순 @@ -567,10 +563,10 @@ 오래된 순 옥색 딸기 칵테일 - 확장기능 목록 취득 실패 + 확장 앱 목록 가져오기 실패 서재 업데이트 시 트래커 갱신 제외: %s - 이 확장기능은 공식 확장기능이 아닙니다. + 이 확장앱은 공식 확장앱이 아닙니다. 트래커 서비스에 항목 진행 상황을 동기화합니다. 트래킹 버튼을 이용하여 각각의 항목 별로 트래킹을 설정하세요. 트래커 가이드 향상된 서비스 @@ -613,11 +609,11 @@ 새로고침 청사과 문어 - 음과 양 + Yin & Yang 요츠바 - 후방주의 (19금) 소스 + 성인 콘텐츠 소스 소스 및 확장 기능 목록에 보이기 - 이 옵션을 끄더라도 비공식 또는 분류가 잘못된 확장 기능으로 인하여 후방주의 (19금) 컨텐츠가 표시될 수 있습니다. + 이 옵션을 끄더라도 비공식 또는 분류가 잘못된 확장 기능으로 인하여 성인 컨텐츠가 표시될 수 있습니다. 터치하여 자세히 보기 3일 제한: %s @@ -686,7 +682,7 @@ 읽을 때 자동 다운로드 마지막 서재 업데이트: %s - 현재 회차 + 다음 회차가 이미 다운로드된 경우에만 작동됩니다 + 현재 회차 + 다음 회차가 이미 다운로드된 경우에만 작동됩니다. 인기 정말로 실행합니까\? 만화에 업데이트가 필요하지 않음으로 건너뜀 @@ -788,4 +784,18 @@ 다운로드 인덱스를 제거함 다음 업데이트 예정 탭하여 Cloudflare에 관한 도움말 보기 + 일별 가져오기 (10일 이상) + %s를 잠금해제 + 항상 업데이트 하도록 설정 + 서재를 동기화합니다 + 백업 파일을 생성할 수 없습니다 + 서재가 동기화되었습니다 + 이 시리즈를 맨 아래로 이동 + 라이센스 제한 - 회차를 표시할 수 없습니다 + 인터넷에 연결되지 않음 + 포기했나요\? 20일 ~ 2달 이내 + 항상 평가하기 + 트랙킹 서비스 로그인 + HTTP %d, WebView의 웹 사이트를 확인해 주세요 + %s에 연결할 수 없습니다 \ No newline at end of file diff --git a/i18n/src/main/res/values-lt/strings.xml b/i18n/src/main/res/values-lt/strings.xml index 820fc3087..dedfc760e 100644 --- a/i18n/src/main/res/values-lt/strings.xml +++ b/i18n/src/main/res/values-lt/strings.xml @@ -48,12 +48,6 @@ Portretas Elementai eilutėje Rodinys - - Vakar - Prieš %1$d dienas - Prieš %1$d dienų - - Šiandien Tai nesustabdo neoficialių ar potencialiai neteisingai pažymėtų plėtinių nuo N18+ turinio rodymo programoje. Rodyti šaltiniuose ir plėtinių sąrašuose N18+ šaltiniai diff --git a/i18n/src/main/res/values-lv/strings.xml b/i18n/src/main/res/values-lv/strings.xml index 899565ddf..0b1c36b23 100644 --- a/i18n/src/main/res/values-lv/strings.xml +++ b/i18n/src/main/res/values-lv/strings.xml @@ -222,17 +222,11 @@ Valoda Nodaļas ieneses datums - - Šodien - Vakar - Pirms %1$d dienām - Izlaist ierakstu atjaunināšanu Biežāk uzdotie jautājumi un rokasgrāmatas Aizvērt Globāls atjauninājums Šis neliedz neoficiāliem vai, iespējams, nepareizi atzīmētiem paplašinājumiem parādīties NSFW (18+) saturu lietotnē. - Šodien Automātiskie atjauninājumi Katru nedēļu Automātiskās atjaunināšanas ierīču ierobežojumi diff --git a/i18n/src/main/res/values-ms/strings.xml b/i18n/src/main/res/values-ms/strings.xml index 45fda159a..7e5f72fbd 100644 --- a/i18n/src/main/res/values-ms/strings.xml +++ b/i18n/src/main/res/values-ms/strings.xml @@ -571,10 +571,6 @@ Sensitiviti menyembunyikan menu apabila skrol Aktiviti latar belakang Songsang - - %1$d hari lalu - - Hari ini Teal & Turquoise Sahkan untuk mengesahkan perubahan Lalai diff --git a/i18n/src/main/res/values-nb-rNO/strings.xml b/i18n/src/main/res/values-nb-rNO/strings.xml index ce9561b16..4cf7a33fb 100644 --- a/i18n/src/main/res/values-nb-rNO/strings.xml +++ b/i18n/src/main/res/values-nb-rNO/strings.xml @@ -132,7 +132,7 @@ Ingen animasjon Normal Rask - Standard rotasjonstype + Standard rotasjon Fri Låst stående Låst liggende @@ -259,9 +259,9 @@ Rutenettstørrelse Denne utvidelsen ble signert med et usikkert sertifikat, og ble dermed ikke aktivert \n -\nEn skadelig utvidelse kan lese innloggingsdetaljer lagret i Tachiyomi, eller kjøre ukjent kode. +\nEn skadelig utvidelse kan lese alle lagrede innloggingsdetaljer eller kjøre vilkårlig kode. \n -\nVed å godta dette sertifikatet aksepterer du overstående risikoer. +\nVed å godta dette sertifikatet aksepterer du disse risikoene. Animasjonshastighet ved dobbelklikk Sider Bruk dette bildet som omslag\? @@ -337,7 +337,7 @@ Meny Kilder Utvidelsesoppdateringer - Tachiyomi krever WebView + Appen fungerer ikke uten WebView Legg til sporing Mindre Mer @@ -411,7 +411,7 @@ Gjort på %1$s med %2$s feil Vis lesemodus - Denne utvidelsen kommer ikke fra den offisielle Tachiyomi-utvidelseslisten. + Denne utvidelsen kommer ikke fra den offisielle listen. deaktivere deaktiver alle aktiver alle @@ -532,7 +532,7 @@ Denne Android-versjonen støttes ikke lenger Liggende Stående - Rotasjonstype + Rotasjon Oppretter mapper i henhold til oppføringenes tittel Lagre sider i egne mapper Handlinger @@ -566,11 +566,6 @@ Av Begrensninger: %s - - I går - %1$d dager siden - - I dag Dynamisk Programdrakt Utseende @@ -813,4 +808,9 @@ Kunne ikke opprette en backup-fil Lisensiert - Ingen kapitler å vise Sporingsinnlogging + Lås opp %s + Flytt serien til bunnen + Ingen internettforbindelse + HTTP %d, sjekk nettsiden i WebView + Kunne ikke nå %s \ No newline at end of file diff --git a/i18n/src/main/res/values-ne/strings.xml b/i18n/src/main/res/values-ne/strings.xml index edec1498a..fb7081339 100644 --- a/i18n/src/main/res/values-ne/strings.xml +++ b/i18n/src/main/res/values-ne/strings.xml @@ -3,7 +3,7 @@ अन अफ अँध्यारो मोड - थिम + थीम बारेमा उन्नत सेटिङहरू ट्र्याकिङ @@ -132,11 +132,6 @@ ल्याण्डस्केप ग्रिड साइज प्रदर्शन - - हिजो - %1$d दिन अघि - - आज स्रोत र एक्सटेन्शन सूची मा देखाउनुहोस् NSFW (१८+) स्रोतहरू सूचना को सामग्री लुकाउनुहोस् @@ -162,7 +157,7 @@ मिडनाइट डस्क हरियो स्याउ गतिशील - एपको थिम + एपको थीम सिस्टम पालना गर्नुहोस् रूप अहिले डाउनलोड गर्न सुरु गर्नुहोस् @@ -170,7 +165,7 @@ क्रमबद्ध यी श्रृङ्खलाका सबै रद्द गर्नुहोस् लोकल स्रोत - WebViewमा खोल्नुहोस् + WebView मा खोल्नुहोस् परिवर्तन पुष्टि गर्न प्रमाणित गर्नुहोस् पूर्वनिर्धारित ट्याब्लेट UI @@ -200,7 +195,7 @@ स्थापना गरियो विश्वास यो एक्सटेन्शन अब उपलब्ध छैन। यसले राम्ररी काम नगर्न सक्छ र एपमा समस्या ल्याउन सक्छ। यसलाई अनइन्स्टल गर्न सिफारिस गरिन्छ। - यो एक्सटेन्शन आधिकारिक ताचियोमीको एक्सटेन्शन सूचीबाट होइन। + यो एक्सटेन्शन आधिकारिक सूचीबाट होइन। यस एक्सटेन्शनको स्रोतहरूमा NSFW (१८+) सामग्री समावेश हुन सक्छ एक्सटेन्शन स्थापना गर्दै… Shizuku चलिरहेको छैन @@ -263,9 +258,9 @@ अविश्वसनीय एक्सटेन्शन समावेश नगर्नुहोस्: %s इंस्टलर - यो एक्सटेन्शन एक अविश्वसनीय प्रमाणपत्र संग हस्ताक्षर गरिएको थियो र सक्रिय गरिएको थिएन। + यो एक्सटेन्शन अविश्वसनीय प्रमाणपत्र सँग हस्ताक्षर गरिएको थियो र सक्रिय गरिएको थिएन। \n -\nएउटा खराब एक्सटेन्शनले ताचियोमीमा भण्डारण गरिएका कुनै पनि लगइन प्रमाणहरू पढ्न वा स्वेच्छाचारी कोड कार्यान्वयन गर्न सक्छ। +\nएक खराब एक्सटेन्शनले कुनै पनि भण्डारण लगइन प्रमाणहरू पढ्न वा मनमानी कोड कार्यान्वयन गर्न सक्छ। \n \nयस प्रमाणपत्रमा विश्वास गरेर तपाईंले यी जोखिमहरू स्वीकार गर्नुहुन्छ। पूर्ण स्क्रिन @@ -300,8 +295,8 @@ सामान्य कुनै एनिमेसन छैन छिटो - पूर्वनिर्धारित रोटेशन प्रकार - रोटेशन प्रकार + पूर्वनिर्धारित रोटेशन + रोटेशन फ्री ल्याण्डस्केप लक गरिएको ल्याण्डस्केप @@ -626,7 +621,7 @@ त्रुटिहरू कुनै अध्याय नपढेकाले छोडियो ठूला अपडेटहरूले स्रोतहरूलाई हानि पुर्‍याउँछ र यसले ढिलो अपडेटहरू निम्त्याउन सक्छ र ब्याट्रीको प्रयोग पनि बढाउँछ। थप जान्न ट्याप गर्नुहोस्। - ताचियोमी को लागि WebView आवश्यक छ + एप काम गर्नका लागि WebView आवश्यक छ श्रृङ्खलालाई शीर्षमा सर्नुहोस् पोर्ट्रेट उल्ट्याउनु नपढिएका अध्यायहरू भएका कारण छोडियो @@ -669,7 +664,7 @@ डाउनलोड गरिएको मापन नगरिएको नेटवर्कमा मात्र अगाडि डाउनलोड गर्नुहोस् - थिम, मिति र समय ढाँचा + थीम, मिति र समय ढाँचा हालको अध्याय + अर्को पहिले नै डाउनलोड गरिएमा मात्र काम गर्दछ। समुन्द्री लहर संस्करण @@ -816,4 +811,6 @@ इन्टरनेट जडान छैन %s मा पुग्न सकिएन HTTP %d, WebView मा वेबसाइट जाँच गर्नुहोस् + अनलक %s + श्रृङ्खलालाई तल सार्नुहोस् \ No newline at end of file diff --git a/i18n/src/main/res/values-nl/strings.xml b/i18n/src/main/res/values-nl/strings.xml index 06ea1cc29..537758d20 100644 --- a/i18n/src/main/res/values-nl/strings.xml +++ b/i18n/src/main/res/values-nl/strings.xml @@ -587,11 +587,6 @@ Hoogste Sensitiviteit voor het verbergen van het menu tijdens scrollen Omgekeerd - - Gisteren - %1$d dagen geleden - - Vandaag Blauwgroen & Turkoois Uiterlijk Authenticeer om de wijziging te bevestigen @@ -770,13 +765,13 @@ Interval aanpassen Download Index geïnvalideerd - - + + Maak de downloadindex ongeldig - - + + OK Swipe naar de linker actie diff --git a/i18n/src/main/res/values-nn/strings.xml b/i18n/src/main/res/values-nn/strings.xml index ece30340f..7621597f7 100644 --- a/i18n/src/main/res/values-nn/strings.xml +++ b/i18n/src/main/res/values-nn/strings.xml @@ -106,11 +106,6 @@ Etter %1$s minuttar NSFW (18+) kjeder - I dag - - I går - %1$d dagar sidan - Skjerm Element per rad Automatisk oppdateringar diff --git a/i18n/src/main/res/values-pl/strings.xml b/i18n/src/main/res/values-pl/strings.xml index e208a925c..133eedb8f 100644 --- a/i18n/src/main/res/values-pl/strings.xml +++ b/i18n/src/main/res/values-pl/strings.xml @@ -595,12 +595,6 @@ Truskawkowe daiquiri Czułość ukrywania dolnego paska podczas przewijania Tako - - Wczoraj - %1$d dni temu - %1$d dni temu - %1$d dni temu - Aktywność w tle Śledź Wygląd @@ -616,7 +610,6 @@ Najwyższy Odwrócone Informacje o aplikacji - Dzisiaj Błękitny & Turkusowy Zmierzch północy Ostrzeżenie: duże aktualizacje biblioteki mogą prowadzić do zwiększonego zużycia baterii oraz spowolnienia działania źródeł. Kliknij, by dowiedzieć się więcej. diff --git a/i18n/src/main/res/values-pt-rBR/strings.xml b/i18n/src/main/res/values-pt-rBR/strings.xml index 3b7f69478..c659954bb 100644 --- a/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/i18n/src/main/res/values-pt-rBR/strings.xml @@ -112,7 +112,7 @@ Esquerda Direita Centro - Tipo de orientação padrão + Orientação padrão Automática Retrato bloqueado Paisagem bloqueado @@ -546,7 +546,7 @@ Cria as pastas usando os títulos dos itens Salvar as páginas em pastas separadas Ações - Tipo de orientação + Orientação Nível de cinza Desabilitar o modo anônimo Auto @@ -593,12 +593,6 @@ Mais alta Sensibilidade para ocultar o menu na rolagem Invertido - - Ontem - %1$d dias atrás - %1$d dias atrás - - Hoje Azul-petróleo & Turquesa Autentique-se para confirmar a mudança Padrão diff --git a/i18n/src/main/res/values-pt/strings.xml b/i18n/src/main/res/values-pt/strings.xml index f0a0dd8e5..2bf2282a3 100644 --- a/i18n/src/main/res/values-pt/strings.xml +++ b/i18n/src/main/res/values-pt/strings.xml @@ -617,12 +617,6 @@ Atualizar monitorizadores ao atualizar biblioteca Guia de introdução Azul-petróleo e Turquesa - - Ontem - Há %1$d dias - Há %1$d dias - - Hoje Dinâmico Aviso Autentifique-se para confirmar a mudança diff --git a/i18n/src/main/res/values-ro/strings.xml b/i18n/src/main/res/values-ro/strings.xml index 1fa29539a..94f50f727 100644 --- a/i18n/src/main/res/values-ro/strings.xml +++ b/i18n/src/main/res/values-ro/strings.xml @@ -602,7 +602,6 @@ Ar trebui să păstrați copii ale backupurilor și în alte locuri. Îmbunătățește performanța cititorului Închide - Azi Listă de citit Lista de dorințe Lista completă @@ -649,11 +648,6 @@ Nu s-a putut obține lista de extensii Se instalează extensia… Program instalare - - Ieri - Acum %1$d zile - Acum %1$d zile - Creează dosare în funcție de titlul intrărilor Automat Pornit diff --git a/i18n/src/main/res/values-ru/strings.xml b/i18n/src/main/res/values-ru/strings.xml index e8c850ca3..6bbc8fd83 100644 --- a/i18n/src/main/res/values-ru/strings.xml +++ b/i18n/src/main/res/values-ru/strings.xml @@ -604,13 +604,6 @@ Самая высокая Чувствительность скрытия меню при прокрутке Цвета наоборот - - Вчера - %1$d дня назад - %1$d дней назад - %1$d дней назад - - Сегодня Бирюзовая Выполните аутентификацию, чтобы подтвердить изменение По умолчанию @@ -849,4 +842,5 @@ Нет подключения к интернету Не удалось достичь %s Разблокировать %s + Переместить серию в конец \ No newline at end of file diff --git a/i18n/src/main/res/values-sa/strings.xml b/i18n/src/main/res/values-sa/strings.xml index 25834e3e2..055b1442b 100644 --- a/i18n/src/main/res/values-sa/strings.xml +++ b/i18n/src/main/res/values-sa/strings.xml @@ -152,11 +152,6 @@ अभिरक्षणपटलम् अनुप्रयोगाणां परिवर्तने अनुप्रयोगवस्तु वृणोति पटलप्रतिकृतीनां च सृष्टिं निवारयति॥ प्रौढानां कृते एव (१८+) वस्तुमूलानि मूलानां विस्ताराणां च सूचीषु दर्शयतु - अद्य - - ह्यः - द्विदिनपूर्वम् - प्रतिपङ्क्तौ वस्तूनि अनुप्रस्थम् प्रदर्शनम् diff --git a/i18n/src/main/res/values-sc/strings.xml b/i18n/src/main/res/values-sc/strings.xml index 8d4b42c45..81d71b045 100644 --- a/i18n/src/main/res/values-sc/strings.xml +++ b/i18n/src/main/res/values-sc/strings.xml @@ -582,11 +582,6 @@ Sensibilidade pro cuare su menù cun s\'iscurrimentu Atividade in s\'isfundu Furriada - - Eris - %1$d dies a oe - - Oe Birde abba e turchesu Autèntica·ti pro cunfirmare sa modìfica Predefinida diff --git a/i18n/src/main/res/values-sdh/strings.xml b/i18n/src/main/res/values-sdh/strings.xml index 65edfe421..b01232095 100644 --- a/i18n/src/main/res/values-sdh/strings.xml +++ b/i18n/src/main/res/values-sdh/strings.xml @@ -168,7 +168,6 @@ سکرین شۆت بلۆکردن و شاردنەوەی ناوەڕۆک، لە کاتی گۆڕین و دەرچوون لە بەرنامە سەرچاوەی سەروو (18) ساڵ پیشاندان لە لیستی سەرچاوە و زیادکراوەکان - ئەمڕۆ شێوازی پیشاندان نوێکردنەوەی تۆماری ڕابردوو…( (%2$d) / (%1$d) ) نەرمە لێدانی پێچەوانە @@ -190,10 +189,6 @@ پاش 1 خولەک پاش %1$s خولەک - - دوێنێ - %1$d ڕۆژ پێش ئێستا - بەدواداچوون زیاد بکە کردنە ناو کۆکراوەکان تکایە مانگا بۆ کۆکراوەکان زیاد بکە پێش کردنی ئەمە diff --git a/i18n/src/main/res/values-sk/strings.xml b/i18n/src/main/res/values-sk/strings.xml index 699246092..b65c9d614 100644 --- a/i18n/src/main/res/values-sk/strings.xml +++ b/i18n/src/main/res/values-sk/strings.xml @@ -395,17 +395,11 @@ Preskočiť aktualizáciu záznamov Zobraziť v zoznamoch zdrojov a rozšírení NSFW (18+) zdroje - Dnes Iba na Wi-Fi Obmedzenia: %s S neprečítanými kapitolami Ktoré sa ešte nezačali Toto nastavenie avšak nebráni tomu, aby sa v aplikácii objavil neoficiálny alebo potenciálne nesprávne označený obsah NSFW (18+). - - Včera - Pred %1$d dňami - Pred %1$d dňami - Globálna aktualizácia Automatický obnoviť metadata Pri aktualizácii knižnice skontrolujte nový obal a podrobnosti diff --git a/i18n/src/main/res/values-sq/strings.xml b/i18n/src/main/res/values-sq/strings.xml index f992c611b..375bc46fa 100644 --- a/i18n/src/main/res/values-sq/strings.xml +++ b/i18n/src/main/res/values-sq/strings.xml @@ -49,11 +49,6 @@ Ekran i sigurt Burimet NSFW (18+) Shfaq në listat e burimeve dhe shtesave - Sot - - Dje - %1$d ditë më parë - Shfaqja Artikuj për rresht Përditësim global diff --git a/i18n/src/main/res/values-sr/strings.xml b/i18n/src/main/res/values-sr/strings.xml index 0a66772ff..e29bd6f4d 100644 --- a/i18n/src/main/res/values-sr/strings.xml +++ b/i18n/src/main/res/values-sr/strings.xml @@ -431,11 +431,6 @@ Потпуно црна тема NSFW - извори за одрасле (18+) Показати у листи за изворе и додатке - - Pre %1$d dan - Pre %1$d dana - Pre %1$d dana - Начин читања Инсталер @@ -566,7 +561,6 @@ Грешке Подешавања поглавља - Данас Лево Још немате категорија. Информације о апликацији diff --git a/i18n/src/main/res/values-sv/strings.xml b/i18n/src/main/res/values-sv/strings.xml index 509b508f9..b953892dd 100644 --- a/i18n/src/main/res/values-sv/strings.xml +++ b/i18n/src/main/res/values-sv/strings.xml @@ -137,7 +137,7 @@ Ingen animering Normal Snabb - Standardrotationstyp + Standard rotation Upplåst Låst porträtt Låst liggande @@ -532,7 +532,7 @@ Kunde inte kopiera till urklipp Liggande Porträtt - Rotationstyp + Rotation Skapa mappar enligt posternas titel Spara sidor i separata mappar Åtgärder @@ -582,11 +582,6 @@ Högsta Känslighet för att dölja menyn vid rullning Omvänd - - Igår - För %1$d dagar sedan - - Idag Teal och turkos Utseende Autentisera för att bekräfta ändringen @@ -817,4 +812,5 @@ HTTP %d, kolla på webbsida i WebView Kunde inte nå %s Lås upp %s + Flytta serien till botten \ No newline at end of file diff --git a/i18n/src/main/res/values-th/strings.xml b/i18n/src/main/res/values-th/strings.xml index c6550e937..086a071a1 100644 --- a/i18n/src/main/res/values-th/strings.xml +++ b/i18n/src/main/res/values-th/strings.xml @@ -138,7 +138,7 @@ ไม่มีแอนิเมชั่น ปกติ เร็ว - ประเภทการหมุนเริ่มต้น + การหมุนเริ่มต้น อิสระ ล็อกแนวตั้ง ล็อกแนวนอน @@ -400,7 +400,7 @@ ช่องว่างด้านข้าง การอ่าน โหมดการอ่าน - ประเภทการหมุน + การหมุน โซนการแตะ หน้ายาวแยกช่องว่าง ขวา @@ -530,7 +530,6 @@ คุณยังไม่มีหมวดหมู่ ยืนยันการเปลี่ยนแปลง - วันนี้ มีตอนที่ยังไม่ได้อ่าน ปิด เปิด @@ -563,9 +562,6 @@ โหลดตัวติดตามใหม่โดยอัตโนมัติ อัปเดตตัวติดตามเมื่ออัปเดตคลัง เริ่มดาวน์โหลดเลย - - %1$d วันที่ผ่านมา - บริการขั้นสูง ควรเก็บสำเนาของข้อมูลสำรองไว้ที่อื่นด้วยเช่นกัน บันทึกบันทึกอย่างละเอียดไปยังบันทึกของระบบ (ลดประสิทธิภาพของแอป) @@ -801,4 +797,5 @@ ไม่มีการเชื่อมต่ออินเทอร์เน็ต HTTP %d, ดูเว็บไซต์ใน WebView ไม่สามารถเข้าถึง %s ได้ + ย้ายเรื่องไปด้านล่าง \ No newline at end of file diff --git a/i18n/src/main/res/values-tr/strings.xml b/i18n/src/main/res/values-tr/strings.xml index e2cfd0824..399e8f567 100644 --- a/i18n/src/main/res/values-tr/strings.xml +++ b/i18n/src/main/res/values-tr/strings.xml @@ -137,7 +137,7 @@ Animasyon yok Normal Hızlı - Ön tanımlı döndürme türü + Ön tanımlı döndürme Bağımsız Kilitli dikey Kilitli yatay @@ -532,7 +532,7 @@ Panoya kopyalanamadı Yatay Dikey - Döndürme türü + Döndürme Girdilerin başlığına göre sıralaç oluşturur Sayfaları ayrı sıralaçlara kaydet Eylemler @@ -582,11 +582,6 @@ En yüksek Kaydırmada komut-seçenek dizelgesini gizleme duyarlılığı Ters Çevrilmiş - - Dün - %1$d gün önce - - Bugün Deniz kökçesi & Türk kökçesi Değişikliği onaylamak için kimlik doğrula Varsayılan @@ -630,7 +625,7 @@ SSS ve Kılavuzlar Okunmayan bölümü olan Bu başlamadı - Manga bitirildiği için atlandı + Dizi bitirildiği için atlandı Okunmamış bölümler olduğu için atlandı Hiçbir bölüm okunmadığı için atlandı Geniş görüntüleri kaydır @@ -817,4 +812,5 @@ Genel ağ bağlantısı yok Kitaplık eşleştiriliyor Aç: %s + Diziyi en alta taşı \ No newline at end of file diff --git a/i18n/src/main/res/values-uk/strings.xml b/i18n/src/main/res/values-uk/strings.xml index 33976dc75..901359183 100644 --- a/i18n/src/main/res/values-uk/strings.xml +++ b/i18n/src/main/res/values-uk/strings.xml @@ -99,7 +99,7 @@ Ненадійне розширення Це розширення було підписано ненадійним сертифікатом та не було активовано. \n -\nЗловмисне розширення может зчитувати будь-які облікові дані для входу, що зберігаються в Tachiyomi, або виконувати довільний код. +\nШкідливе розширення може зчитувати будь-які збережені облікові дані для входу або виконати довільний код. \n \nДовіряючи цьому сертифікату, ви приймаєте ці ризики. Повноекранний режим @@ -137,7 +137,7 @@ Без анімації Нормальна Швидка - Тип основної орієнтації + Орієнтація за замовчуванням Вільна Заблокована портретна Заблокована альбомна @@ -386,13 +386,13 @@ Додати до бібліотеки Менше Більше - WebView необхідний для Tachiyomi + WebView необхідний для роботи застосунку Ліцензії з відкритим кодом Сторінка Тільки завантажені Сірий Зменшує смугастість, але може вплинути на продуктивність - Це розширення не входить до переліку офіційних розширень Tachiyomi. + Це розширення не з офіційного списку. Неофіційне %d категорія @@ -553,7 +553,7 @@ Не вдалось скопіювати до буферу обміну Альбомна Портретна - Тип орієнтації + Орієнтація Створювати теки в відповідності до назви записів Зберігати сторінки до окремих тек Дії @@ -603,13 +603,6 @@ Тема застосунку Розпочати завантаження зараз Інвертовано - - Учора - %1$d днів тому - %1$d днів тому - %1$d днів тому - - Сьогодні Бірюзова Виконайте автентифікацію, щоб підтвердити зміну Типово @@ -844,4 +837,9 @@ Натисніть тут, щоб отримати допомогу з Cloudflare Не вдалося створити файл резервної копії Ліцензовано - немає розділів для показу + Розблокувати %s + Перемістити серію вниз + Немає Інтернет-з\'єднання + Http %d, перевірте вебсайт у WebView + Не вдалося досягти %s \ No newline at end of file diff --git a/i18n/src/main/res/values-uz/strings.xml b/i18n/src/main/res/values-uz/strings.xml index 9b2703dbe..ac6548fcb 100644 --- a/i18n/src/main/res/values-uz/strings.xml +++ b/i18n/src/main/res/values-uz/strings.xml @@ -178,7 +178,6 @@ Ilova ekrani himoyasi Manbaa va kengaytmalar ro\'yhatida ko\'rsatish Bu, ilovada norasmiy yoki noto\'g\'ri belgilangan kengaytmalardan NSFW (18+) kontent paydo bo\'lishini oldini olmaydi. - Bugun Ko\'rsatish Qismlar soni Qism boshlanmagan @@ -246,10 +245,6 @@ O\'qish boshlanganida o\'qish rejimini birozga ko\'rsatish Qism yakunlangan Kengaytma o\'rnatilmoqda… - - Kecha - %1$d kun oldin - Global yangilanish Metama\'lumotlarni yangilash Istisno qilish: %s diff --git a/i18n/src/main/res/values-vi/strings.xml b/i18n/src/main/res/values-vi/strings.xml index e37aebf1b..77b236fec 100644 --- a/i18n/src/main/res/values-vi/strings.xml +++ b/i18n/src/main/res/values-vi/strings.xml @@ -613,10 +613,6 @@ Cao Cao nhất Đảo màu - - %1$d ngày trước - - Hôm nay Hỗ trợ dịch thuật Thông tin ứng dụng Cài và chạy Shizuku để sử dụng Shizuku như một trình cài đặt tiện ích mở rộng. diff --git a/i18n/src/main/res/values-zh-rCN/strings.xml b/i18n/src/main/res/values-zh-rCN/strings.xml index 2a32f659f..a7357a732 100644 --- a/i18n/src/main/res/values-zh-rCN/strings.xml +++ b/i18n/src/main/res/values-zh-rCN/strings.xml @@ -571,10 +571,6 @@ 最高 滑动时隐藏菜单的灵敏度 反色 - 今天 - - %1$d 天前 - 青色与绿松色 验证以确认更改 默认 diff --git a/i18n/src/main/res/values-zh-rTW/strings.xml b/i18n/src/main/res/values-zh-rTW/strings.xml index 6fdde8a91..5f19cf8af 100644 --- a/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/i18n/src/main/res/values-zh-rTW/strings.xml @@ -574,10 +574,6 @@ 綠松色 驗證以確認變更 外觀 - 今天 - - %1$d 天前 - 預設 平板電腦介面 入門指南 @@ -801,4 +797,5 @@ 沒有網際網路連線 無法連上 %s 解鎖 %s + 將系列移至底部 \ No newline at end of file From 86edce0d8705beb4f7f750a0c6f5fa4b353ec3c0 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 24 Sep 2023 17:26:12 -0400 Subject: [PATCH 36/59] Bring back relative timestamp translations --- .../java/eu/kanade/presentation/history/HistoryScreen.kt | 1 - i18n/src/main/res/values-ar/strings.xml | 9 +++++++++ i18n/src/main/res/values-b+es+419/strings.xml | 6 ++++++ i18n/src/main/res/values-be/strings.xml | 7 +++++++ i18n/src/main/res/values-bg/strings.xml | 5 +++++ i18n/src/main/res/values-bn/strings.xml | 5 +++++ i18n/src/main/res/values-ca/strings.xml | 5 +++++ i18n/src/main/res/values-ceb/strings.xml | 5 +++++ i18n/src/main/res/values-cs/strings.xml | 6 ++++++ i18n/src/main/res/values-cv/strings.xml | 5 +++++ i18n/src/main/res/values-da/strings.xml | 5 +++++ i18n/src/main/res/values-de/strings.xml | 5 +++++ i18n/src/main/res/values-el/strings.xml | 5 +++++ i18n/src/main/res/values-eo/strings.xml | 5 +++++ i18n/src/main/res/values-es/strings.xml | 6 ++++++ i18n/src/main/res/values-eu/strings.xml | 5 +++++ i18n/src/main/res/values-fa/strings.xml | 5 +++++ i18n/src/main/res/values-fi/strings.xml | 5 +++++ i18n/src/main/res/values-fil/strings.xml | 5 +++++ i18n/src/main/res/values-fr/strings.xml | 6 ++++++ i18n/src/main/res/values-gl/strings.xml | 5 +++++ i18n/src/main/res/values-he/strings.xml | 7 +++++++ i18n/src/main/res/values-hi/strings.xml | 5 +++++ i18n/src/main/res/values-hr/strings.xml | 6 ++++++ i18n/src/main/res/values-hu/strings.xml | 5 +++++ i18n/src/main/res/values-in/strings.xml | 4 ++++ i18n/src/main/res/values-it/strings.xml | 6 ++++++ i18n/src/main/res/values-ja/strings.xml | 4 ++++ i18n/src/main/res/values-jv/strings.xml | 4 ++++ i18n/src/main/res/values-kk/strings.xml | 5 +++++ i18n/src/main/res/values-km/strings.xml | 4 ++++ i18n/src/main/res/values-ko/strings.xml | 4 ++++ i18n/src/main/res/values-lt/strings.xml | 6 ++++++ i18n/src/main/res/values-lv/strings.xml | 6 ++++++ i18n/src/main/res/values-ms/strings.xml | 4 ++++ i18n/src/main/res/values-nb-rNO/strings.xml | 5 +++++ i18n/src/main/res/values-ne/strings.xml | 5 +++++ i18n/src/main/res/values-nl/strings.xml | 5 +++++ i18n/src/main/res/values-nn/strings.xml | 5 +++++ i18n/src/main/res/values-pl/strings.xml | 7 +++++++ i18n/src/main/res/values-pt-rBR/strings.xml | 6 ++++++ i18n/src/main/res/values-pt/strings.xml | 6 ++++++ i18n/src/main/res/values-ro/strings.xml | 6 ++++++ i18n/src/main/res/values-ru/strings.xml | 7 +++++++ i18n/src/main/res/values-sa/strings.xml | 5 +++++ i18n/src/main/res/values-sc/strings.xml | 5 +++++ i18n/src/main/res/values-sdh/strings.xml | 5 +++++ i18n/src/main/res/values-sk/strings.xml | 6 ++++++ i18n/src/main/res/values-sq/strings.xml | 5 +++++ i18n/src/main/res/values-sr/strings.xml | 6 ++++++ i18n/src/main/res/values-sv/strings.xml | 5 +++++ i18n/src/main/res/values-th/strings.xml | 4 ++++ i18n/src/main/res/values-tr/strings.xml | 5 +++++ i18n/src/main/res/values-uk/strings.xml | 7 +++++++ i18n/src/main/res/values-uz/strings.xml | 5 +++++ i18n/src/main/res/values-vi/strings.xml | 4 ++++ i18n/src/main/res/values-zh-rCN/strings.xml | 4 ++++ i18n/src/main/res/values-zh-rTW/strings.xml | 4 ++++ .../presentation/core/components/AdaptiveSheet.kt | 1 + 59 files changed, 303 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt b/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt index fc755c922..45dc67fdb 100644 --- a/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt @@ -27,7 +27,6 @@ import tachiyomi.presentation.core.screens.EmptyScreen import tachiyomi.presentation.core.screens.LoadingScreen import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import java.text.DateFormat import java.util.Date @Composable diff --git a/i18n/src/main/res/values-ar/strings.xml b/i18n/src/main/res/values-ar/strings.xml index 718a2c18c..399f5c0da 100644 --- a/i18n/src/main/res/values-ar/strings.xml +++ b/i18n/src/main/res/values-ar/strings.xml @@ -624,9 +624,18 @@ قد لا يعمل النسخ الاحتياطيُّ أو الاستعادة إن عطِّلت أمثَلَة MIUI. الخدمات التي تقدم ميزات محسنة لأجل مصادر معينه. الإدخالات سوف يتم تتبعها عندما يتم إضافتها الي المكتبة. خدمات محسَّنة + اليوم المصادقة لتأكيد التغيير الافتراضي الأنشطة التي تعمل في الخلفية + + الأمس + منذ %1$d أيام + منذ %1$d أيام + منذ %1$d أيام + منذ %1$d أيام + منذ %1$d أيام + تتبع معكوس ازرق مخضر و فيروز diff --git a/i18n/src/main/res/values-b+es+419/strings.xml b/i18n/src/main/res/values-b+es+419/strings.xml index 743721c47..ede476a22 100644 --- a/i18n/src/main/res/values-b+es+419/strings.xml +++ b/i18n/src/main/res/values-b+es+419/strings.xml @@ -591,6 +591,12 @@ Actualizar rastreadores cuando se actualice la biblioteca Actualizar rastreadores automáticamente Restricciones: %s + + Ayer + Hace %1$d dias + Hace %1$d dias + + Hoy Modo oscuro con negro puro Tema Yotsuba Yin y Yang diff --git a/i18n/src/main/res/values-be/strings.xml b/i18n/src/main/res/values-be/strings.xml index f25eec920..1cefa0e7b 100644 --- a/i18n/src/main/res/values-be/strings.xml +++ b/i18n/src/main/res/values-be/strings.xml @@ -278,6 +278,13 @@ Змясціць у экран Маштабаванне Колеры наадварот + + Учора + %1$d дні таму + %1$d дзён таму + %1$d дзён таму + + Сёння Бірузовы Знешнасць Аўтэнтыфікацыя для пацверджання змяненняў diff --git a/i18n/src/main/res/values-bg/strings.xml b/i18n/src/main/res/values-bg/strings.xml index 0c0c7fdd0..097115845 100644 --- a/i18n/src/main/res/values-bg/strings.xml +++ b/i18n/src/main/res/values-bg/strings.xml @@ -557,6 +557,10 @@ Чувствителност за скриване на менюто при превъртане Най-висока Непрочетена + + Вчера + Преди %1$d дни + Корица Предупреждение Удостоверете, за да потвърдите промяната @@ -621,6 +625,7 @@ Следваща страница Език Показвай в списъка с източници и разширения + Днес Информация Покажи зони за натискане, когато четецът се отвори Обърни позициите на разделените широки страници diff --git a/i18n/src/main/res/values-bn/strings.xml b/i18n/src/main/res/values-bn/strings.xml index 04ddd3487..7f3dc3ef9 100644 --- a/i18n/src/main/res/values-bn/strings.xml +++ b/i18n/src/main/res/values-bn/strings.xml @@ -566,6 +566,11 @@ লাইব্রেরি আপডেট করার সময় ট্র্যাকার আপডেট করুন স্বয়ংক্রিয়ভাবে রিফ্রেশ ট্র্যাকার বিধিনিষেধ: %s + + গতকাল + %1$d দিন আগে + + সম্প্রতি বিশুদ্ধ কালো অন্ধকার মোড চার পাতা ইয়িন এবং ইয়াং diff --git a/i18n/src/main/res/values-ca/strings.xml b/i18n/src/main/res/values-ca/strings.xml index cf45eaeb6..633d812c7 100644 --- a/i18n/src/main/res/values-ca/strings.xml +++ b/i18n/src/main/res/values-ca/strings.xml @@ -567,6 +567,11 @@ Encara no teniu cap categoria. S’està actualitzant la biblioteca… (%1$d/%2$d) Serveis millorats + + Ahir + Fa %1$d dies + + Avui Per defecte Advertència Autentiqueu-vos per a confirmar el canvi diff --git a/i18n/src/main/res/values-ceb/strings.xml b/i18n/src/main/res/values-ceb/strings.xml index cf1808fb3..81529b94c 100644 --- a/i18n/src/main/res/values-ceb/strings.xml +++ b/i18n/src/main/res/values-ceb/strings.xml @@ -135,6 +135,7 @@ Tagoa ang sulod sa pahibalo Lig-on nga screen NSFW (18+) Mga Tinubdan + Karon Pagpakita Mga butang kada laray Hulagway @@ -157,6 +158,10 @@ Human sa %1$s ka minuto Human sa %1$s ka minuto + + Kagahapon + %1$d ka adlaw ang milabay + Nagpaubos Pinaagi sa petsa sa pag-upload Pinaagi sa numero sa kapitulo diff --git a/i18n/src/main/res/values-cs/strings.xml b/i18n/src/main/res/values-cs/strings.xml index 123bffa35..c9aee2595 100644 --- a/i18n/src/main/res/values-cs/strings.xml +++ b/i18n/src/main/res/values-cs/strings.xml @@ -593,6 +593,12 @@ Příručka Začínáme Uživatelské rozhraní tabletu Sledovat + + Včera + Před %1$d dny + Před %1$d dny + + Dnes Modrozelená a Tyrkysová Vzhled Potvrďte změnu ověřením diff --git a/i18n/src/main/res/values-cv/strings.xml b/i18n/src/main/res/values-cv/strings.xml index 17d50a35d..f80d926e7 100644 --- a/i18n/src/main/res/values-cv/strings.xml +++ b/i18n/src/main/res/values-cv/strings.xml @@ -571,12 +571,17 @@ Тийесе илнӗ Шыв хӑпарнин хумӗ Ап темми + Пайан Лавантӑ Ин тата Йан Ҫӑл куҫсем, хушмасем, пӗтӗмӗшле шырав Симӗс пан улми Йутсупа Серилӗхсене ҫӗнетнине сиктер + + Ӗнер + %1$d кун кайалла + Чараксӑр тетел урлӑ ҫеҫ Серилӗхе пуҫламан Такку diff --git a/i18n/src/main/res/values-da/strings.xml b/i18n/src/main/res/values-da/strings.xml index e0a8ea4a0..ccd1e3144 100644 --- a/i18n/src/main/res/values-da/strings.xml +++ b/i18n/src/main/res/values-da/strings.xml @@ -144,9 +144,14 @@ Håndter notifikationer Sikkerhed Kræv oplåsning + + I går + %1$d dage siden + NSFW (18+) kilder Vis i kilder og udvidelsesliste Dette forhindrer ikke uofficielle eller potentielt ukorrekt markerede udvidelser fra at vise NSFW (18+) indhold i appen. + I dag Efter %1$s minut Efter %1$s minutter diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml index 975834b86..052b79f3f 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -582,6 +582,11 @@ Höchste Empfindlichkeit für das Menü-Ausblenden beim Scrollen Invertiert + + Gestern + Vor %1$d Tagen + + Heute Blaugrün & Türkis Erscheinungsbild Authentifiziere dich, um die Änderungen zu bestätigen diff --git a/i18n/src/main/res/values-el/strings.xml b/i18n/src/main/res/values-el/strings.xml index ad05d0eb1..6239e9d66 100644 --- a/i18n/src/main/res/values-el/strings.xml +++ b/i18n/src/main/res/values-el/strings.xml @@ -581,7 +581,12 @@ Ύψιστη Υψηλή Ευαισθησία για την απόκρυψη του μενού κατά την κύλιση + + Εχθές + %1$d μέρες πριν + Αντεστραμμένο + Σήμερα Teal & Τιρκουάζ Έλεγχος ταυτότητας για επιβεβαίωση αλλαγής Προεπιλογή diff --git a/i18n/src/main/res/values-eo/strings.xml b/i18n/src/main/res/values-eo/strings.xml index 074e16dd3..857703896 100644 --- a/i18n/src/main/res/values-eo/strings.xml +++ b/i18n/src/main/res/values-eo/strings.xml @@ -384,6 +384,11 @@ Malŝaltita Ŝaltita Elementoj vice + + Hieraŭ + Antaŭ %1$d tagoj + + Hodiaŭ Jino kaj Jango Verda pomo Apa etoso diff --git a/i18n/src/main/res/values-es/strings.xml b/i18n/src/main/res/values-es/strings.xml index 4fea20f46..eda92c287 100644 --- a/i18n/src/main/res/values-es/strings.xml +++ b/i18n/src/main/res/values-es/strings.xml @@ -627,6 +627,12 @@ Más alta Sensibilidad para ocultar automáticamente el menú al desplazarse Invertido + + Ayer + Hace %1$d días + Hace %1$d días + + Hoy Azul marino y turquesa Apariencia Identifícate para confirmar el cambio diff --git a/i18n/src/main/res/values-eu/strings.xml b/i18n/src/main/res/values-eu/strings.xml index 021838996..77162b700 100644 --- a/i18n/src/main/res/values-eu/strings.xml +++ b/i18n/src/main/res/values-eu/strings.xml @@ -193,6 +193,10 @@ Ez dago aurreko kapitulurik Kopiatu Android bertsio hau jada ez da onartzen + + Atzo + Duela %1$d egun + Zaharkitua Desinstalatu Erakutsi orrialdearen zenbakia @@ -431,6 +435,7 @@ NSFW (18+) iturriak Erakutsi iturrien eta luzapenen zerrendetan Honek ez du eragozten ofizialak ez diren edo oker markatutako luzapenek NSFW (18+) edukia aplikazioan erakustea. + Gaur Bistaratu Errenkada bakoitzeko elementu kopurua Eguneraketa globalak diff --git a/i18n/src/main/res/values-fa/strings.xml b/i18n/src/main/res/values-fa/strings.xml index 47968fd1c..cb38c0439 100644 --- a/i18n/src/main/res/values-fa/strings.xml +++ b/i18n/src/main/res/values-fa/strings.xml @@ -550,9 +550,14 @@ فقط روی شبکه‌ی نامحدود که شروع نشده‌اند محدودیت‌ها: %s + + دیروز + %1$d روز پیش + با قسمت‌(های) خوانده‌نشده ردیاب‌ها را به طور خودکار تازه کن از به‌روزرسانی ورودی‌ها صرف‌نظر کنید + امروز هر 3 روز فقط روی Wi-Fi به‌روزرسانی ردیاب‌ها هنگام به‌روزرسانی کتابخانه diff --git a/i18n/src/main/res/values-fi/strings.xml b/i18n/src/main/res/values-fi/strings.xml index bcb3a865a..c97467e5f 100644 --- a/i18n/src/main/res/values-fi/strings.xml +++ b/i18n/src/main/res/values-fi/strings.xml @@ -552,6 +552,10 @@ Aloitusopas Varoitus: massalataukset voivat johtaa siihen, että lähteet muuttuvat hitaammiksi käyttää ja/tai ne estävät Tachiyomin käytön. Napauta saadaksesi lisätietoja. Päivitä seurantapalvelimet kirjaston päivityksen yhteydessä + + Eilen + %1$d päivää sitten + Näytä manga Kansikuva ruudukko Dynaaminen @@ -569,6 +573,7 @@ Yotsuba Täysin musta pimeätila Ei lukemattomia lukuja + Tänään Sarjalla on lukemattomia kappaleita Sovelluksen teema Varoitus diff --git a/i18n/src/main/res/values-fil/strings.xml b/i18n/src/main/res/values-fil/strings.xml index db931e8d3..475067172 100644 --- a/i18n/src/main/res/values-fil/strings.xml +++ b/i18n/src/main/res/values-fil/strings.xml @@ -582,6 +582,11 @@ Pinakamataas Sensitivity para sa pagtatago ng menu sa scroll Baligtad + + Kahapon + %1$d araw na ang makalipas + + Ngayon Teal at Turquoise Hitsura Patotohanan para makumpirma ang pagbabago diff --git a/i18n/src/main/res/values-fr/strings.xml b/i18n/src/main/res/values-fr/strings.xml index 185b1130b..b6c90e684 100644 --- a/i18n/src/main/res/values-fr/strings.xml +++ b/i18n/src/main/res/values-fr/strings.xml @@ -627,6 +627,12 @@ Maximale Sensibilité pour masquer le menu lors du défilement Inversé + + Hier + Il y a %1$d jours + Il y a %1$d jours + + Aujourd\'hui Bleu canard et turquoise Authentifiez-vous pour confirmer les changements Apparence diff --git a/i18n/src/main/res/values-gl/strings.xml b/i18n/src/main/res/values-gl/strings.xml index 7227d6898..1b58a9ac9 100644 --- a/i18n/src/main/res/values-gl/strings.xml +++ b/i18n/src/main/res/values-gl/strings.xml @@ -261,6 +261,7 @@ Fontes, extensións, procura global Baixar os rexistros de erros, optimizacións de batería Maremoto + Hoxe Con capítulos sin ler Os elementos das categorías excluídas non se actualizarán aínda se están tamén nas categorías incluídas. Versión @@ -508,6 +509,10 @@ Cancelar todo para esta serie Por data de subida Preme para ver os detalles do erro + + Onte + Fai %1$d días + Omitir actualizacións Restricións: %s Opcións de ordenación e visualización por categoría diff --git a/i18n/src/main/res/values-he/strings.xml b/i18n/src/main/res/values-he/strings.xml index 6e71fa14f..d419e9157 100644 --- a/i18n/src/main/res/values-he/strings.xml +++ b/i18n/src/main/res/values-he/strings.xml @@ -379,6 +379,7 @@ מקורות NSFW (18+) הצג ברשימות מקורות ותוספים זה לא מונע תוספים לא רשמיים או תוספים שעלולים לסמן באופן שגוי מלהציג תוכן NSFW (18+) בתוך האפליקציה. + היום תצוגה עדכן עוקבים בעת עדכון הספרייה אפשר הכל @@ -427,6 +428,12 @@ דלג על עדכוני פריטים נכשל בקבלת רשימת ההרחבות שו\"ת ומדריכים + + אתמול + לפני יומיים + לפני %1$d ימים + לפני %1$d ימים + 18+ אין כל 3 ימים diff --git a/i18n/src/main/res/values-hi/strings.xml b/i18n/src/main/res/values-hi/strings.xml index c5f8d458f..d4cff453b 100644 --- a/i18n/src/main/res/values-hi/strings.xml +++ b/i18n/src/main/res/values-hi/strings.xml @@ -559,6 +559,7 @@ परिदृश्य कुल आइटम मिडनाइट डस्क + आज पुस्तकालय अपडेट करते समय ट्रैकर्स को अपडेट करें शामिल करें: %s ऐप की जानकारी @@ -571,6 +572,10 @@ MIUI ऑप्टिमाइज़ेशन अक्षम होने पर बैकअप/पुनर्स्थापना ठीक से काम नहीं कर सकता है। पृष्ठभूमि गतिविधि कुछ निर्माताओं के पास अतिरिक्त ऐप प्रतिबंध हैं जो पृष्ठभूमि सेवाओं को मारते हैं। इस वेबसाइट में इसे ठीक करने के बारे में अधिक जानकारी है। + + कल + %1$d दिन पहले + अमान्य अध्याय प्रारूप के अनुसार ऑर्डर करें क्लिपबोर्ड पर कॉपी करने में विफल diff --git a/i18n/src/main/res/values-hr/strings.xml b/i18n/src/main/res/values-hr/strings.xml index 13ebd5f37..e60b033c4 100644 --- a/i18n/src/main/res/values-hr/strings.xml +++ b/i18n/src/main/res/values-hr/strings.xml @@ -581,6 +581,12 @@ Yotsuba Jin i Jang Invertirano + + Prije %1$d dan + Prije %1$d dana + Prije %1$d dana + + Danas Potpuno crna tamna tema Strawberry Daiquiri Izgled diff --git a/i18n/src/main/res/values-hu/strings.xml b/i18n/src/main/res/values-hu/strings.xml index 3d13e90e4..9df1cbc82 100644 --- a/i18n/src/main/res/values-hu/strings.xml +++ b/i18n/src/main/res/values-hu/strings.xml @@ -338,6 +338,11 @@ Követők automatikus frissítése Polip Eper koktél + + Tegnap + %1$d napja + + Ma Teljesen fekete sötét mód Yotsuba Jin és Jang diff --git a/i18n/src/main/res/values-in/strings.xml b/i18n/src/main/res/values-in/strings.xml index 3f5560f05..1f4824c66 100644 --- a/i18n/src/main/res/values-in/strings.xml +++ b/i18n/src/main/res/values-in/strings.xml @@ -569,6 +569,10 @@ Tinggi Tertinggi Terbalik + + %1$d hari yang lalu + + Hari Ini Panduan awal mulai Lacak Teal & Pirus diff --git a/i18n/src/main/res/values-it/strings.xml b/i18n/src/main/res/values-it/strings.xml index 5204cadce..a6c7c1b04 100644 --- a/i18n/src/main/res/values-it/strings.xml +++ b/i18n/src/main/res/values-it/strings.xml @@ -613,6 +613,12 @@ Più alto Sensibilità per nascondere il menù allo scorrimento Inversa + + Ieri + %1$d giorni fa + %1$d giorni fa + + Oggi Modalità scura con nero puro Yotsuba Yin e Yang diff --git a/i18n/src/main/res/values-ja/strings.xml b/i18n/src/main/res/values-ja/strings.xml index ea2e5feb8..35138b26f 100644 --- a/i18n/src/main/res/values-ja/strings.xml +++ b/i18n/src/main/res/values-ja/strings.xml @@ -568,6 +568,10 @@ 高い 最高 反転配色 + + %1$d日前 + + 今日 翻訳に協力 入門ガイド タブレットUI diff --git a/i18n/src/main/res/values-jv/strings.xml b/i18n/src/main/res/values-jv/strings.xml index 23a7654f6..14b9636aa 100644 --- a/i18n/src/main/res/values-jv/strings.xml +++ b/i18n/src/main/res/values-jv/strings.xml @@ -179,6 +179,10 @@ Ijo apel Takon jawab lan panduan Iki ora nyegah ekstensi kang ora resmi utawa salah dilabeli kanggo nampilake konten NSFW (18+) ing aplikasi. + Dinten puniki + + %1$d dinten kala-wingi + Mati Kaamanan Tansah diff --git a/i18n/src/main/res/values-kk/strings.xml b/i18n/src/main/res/values-kk/strings.xml index 49a02af59..58d841434 100644 --- a/i18n/src/main/res/values-kk/strings.xml +++ b/i18n/src/main/res/values-kk/strings.xml @@ -39,6 +39,10 @@ Бет (солдан оңға қарай) Санаттарыңыз жоқ. Жаңа санат жасау үшін және кітапханаңызды ұйымдастыру үшін қосу батырмасын басыңыз. Келесі + + Кеше + %1$d күн бұрын + Соңғы жаңартуды тексеру Оқылмаған тараулар Тізім @@ -67,6 +71,7 @@ Қызғылт пен жасыл Қап-қараңғы режим Инь мен Йянь + Бүгін Өшірулі Әр 6 сағат сайын Әр 12 сағат сайын diff --git a/i18n/src/main/res/values-km/strings.xml b/i18n/src/main/res/values-km/strings.xml index 626099715..85cbee0ce 100644 --- a/i18n/src/main/res/values-km/strings.xml +++ b/i18n/src/main/res/values-km/strings.xml @@ -141,6 +141,10 @@ ការពារអេក្រង់ ប្រភពមិនល្អ(១៨+) បង្ហាញនៅក្នុងបញ្ចីប្រភព + ថ្ងៃនេះ + + %1$d ថ្ងៃមុន + ការបង្ហាញ ធាតុក្នុងមួយជួ បញ្ឈរ diff --git a/i18n/src/main/res/values-ko/strings.xml b/i18n/src/main/res/values-ko/strings.xml index e9f912b87..e41a78f64 100644 --- a/i18n/src/main/res/values-ko/strings.xml +++ b/i18n/src/main/res/values-ko/strings.xml @@ -387,6 +387,9 @@ 현재 만화에만 적용 읽기 모드 서재의 모든 항목에 적용됩니다 + + %1$d일 전 + 모서리 여백 앱 정보 초기 설정 도움말 @@ -412,6 +415,7 @@ 화면 보안 잠금 해제 필요 모양 + 오늘 전역 업데이트 보안 및 개인정보 보호 diff --git a/i18n/src/main/res/values-lt/strings.xml b/i18n/src/main/res/values-lt/strings.xml index dedfc760e..820fc3087 100644 --- a/i18n/src/main/res/values-lt/strings.xml +++ b/i18n/src/main/res/values-lt/strings.xml @@ -48,6 +48,12 @@ Portretas Elementai eilutėje Rodinys + + Vakar + Prieš %1$d dienas + Prieš %1$d dienų + + Šiandien Tai nesustabdo neoficialių ar potencialiai neteisingai pažymėtų plėtinių nuo N18+ turinio rodymo programoje. Rodyti šaltiniuose ir plėtinių sąrašuose N18+ šaltiniai diff --git a/i18n/src/main/res/values-lv/strings.xml b/i18n/src/main/res/values-lv/strings.xml index 0b1c36b23..899565ddf 100644 --- a/i18n/src/main/res/values-lv/strings.xml +++ b/i18n/src/main/res/values-lv/strings.xml @@ -222,11 +222,17 @@ Valoda Nodaļas ieneses datums + + Šodien + Vakar + Pirms %1$d dienām + Izlaist ierakstu atjaunināšanu Biežāk uzdotie jautājumi un rokasgrāmatas Aizvērt Globāls atjauninājums Šis neliedz neoficiāliem vai, iespējams, nepareizi atzīmētiem paplašinājumiem parādīties NSFW (18+) saturu lietotnē. + Šodien Automātiskie atjauninājumi Katru nedēļu Automātiskās atjaunināšanas ierīču ierobežojumi diff --git a/i18n/src/main/res/values-ms/strings.xml b/i18n/src/main/res/values-ms/strings.xml index 7e5f72fbd..45fda159a 100644 --- a/i18n/src/main/res/values-ms/strings.xml +++ b/i18n/src/main/res/values-ms/strings.xml @@ -571,6 +571,10 @@ Sensitiviti menyembunyikan menu apabila skrol Aktiviti latar belakang Songsang + + %1$d hari lalu + + Hari ini Teal & Turquoise Sahkan untuk mengesahkan perubahan Lalai diff --git a/i18n/src/main/res/values-nb-rNO/strings.xml b/i18n/src/main/res/values-nb-rNO/strings.xml index 4cf7a33fb..f1491264b 100644 --- a/i18n/src/main/res/values-nb-rNO/strings.xml +++ b/i18n/src/main/res/values-nb-rNO/strings.xml @@ -566,6 +566,11 @@ Av Begrensninger: %s + + I går + %1$d dager siden + + I dag Dynamisk Programdrakt Utseende diff --git a/i18n/src/main/res/values-ne/strings.xml b/i18n/src/main/res/values-ne/strings.xml index fb7081339..07c53c4d6 100644 --- a/i18n/src/main/res/values-ne/strings.xml +++ b/i18n/src/main/res/values-ne/strings.xml @@ -132,6 +132,11 @@ ल्याण्डस्केप ग्रिड साइज प्रदर्शन + + हिजो + %1$d दिन अघि + + आज स्रोत र एक्सटेन्शन सूची मा देखाउनुहोस् NSFW (१८+) स्रोतहरू सूचना को सामग्री लुकाउनुहोस् diff --git a/i18n/src/main/res/values-nl/strings.xml b/i18n/src/main/res/values-nl/strings.xml index 537758d20..b69b554d1 100644 --- a/i18n/src/main/res/values-nl/strings.xml +++ b/i18n/src/main/res/values-nl/strings.xml @@ -587,6 +587,11 @@ Hoogste Sensitiviteit voor het verbergen van het menu tijdens scrollen Omgekeerd + + Gisteren + %1$d dagen geleden + + Vandaag Blauwgroen & Turkoois Uiterlijk Authenticeer om de wijziging te bevestigen diff --git a/i18n/src/main/res/values-nn/strings.xml b/i18n/src/main/res/values-nn/strings.xml index 7621597f7..ece30340f 100644 --- a/i18n/src/main/res/values-nn/strings.xml +++ b/i18n/src/main/res/values-nn/strings.xml @@ -106,6 +106,11 @@ Etter %1$s minuttar NSFW (18+) kjeder + I dag + + I går + %1$d dagar sidan + Skjerm Element per rad Automatisk oppdateringar diff --git a/i18n/src/main/res/values-pl/strings.xml b/i18n/src/main/res/values-pl/strings.xml index 133eedb8f..e208a925c 100644 --- a/i18n/src/main/res/values-pl/strings.xml +++ b/i18n/src/main/res/values-pl/strings.xml @@ -595,6 +595,12 @@ Truskawkowe daiquiri Czułość ukrywania dolnego paska podczas przewijania Tako + + Wczoraj + %1$d dni temu + %1$d dni temu + %1$d dni temu + Aktywność w tle Śledź Wygląd @@ -610,6 +616,7 @@ Najwyższy Odwrócone Informacje o aplikacji + Dzisiaj Błękitny & Turkusowy Zmierzch północy Ostrzeżenie: duże aktualizacje biblioteki mogą prowadzić do zwiększonego zużycia baterii oraz spowolnienia działania źródeł. Kliknij, by dowiedzieć się więcej. diff --git a/i18n/src/main/res/values-pt-rBR/strings.xml b/i18n/src/main/res/values-pt-rBR/strings.xml index c659954bb..505208425 100644 --- a/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/i18n/src/main/res/values-pt-rBR/strings.xml @@ -593,6 +593,12 @@ Mais alta Sensibilidade para ocultar o menu na rolagem Invertido + + Ontem + %1$d dias atrás + %1$d dias atrás + + Hoje Azul-petróleo & Turquesa Autentique-se para confirmar a mudança Padrão diff --git a/i18n/src/main/res/values-pt/strings.xml b/i18n/src/main/res/values-pt/strings.xml index 2bf2282a3..f0a0dd8e5 100644 --- a/i18n/src/main/res/values-pt/strings.xml +++ b/i18n/src/main/res/values-pt/strings.xml @@ -617,6 +617,12 @@ Atualizar monitorizadores ao atualizar biblioteca Guia de introdução Azul-petróleo e Turquesa + + Ontem + Há %1$d dias + Há %1$d dias + + Hoje Dinâmico Aviso Autentifique-se para confirmar a mudança diff --git a/i18n/src/main/res/values-ro/strings.xml b/i18n/src/main/res/values-ro/strings.xml index 94f50f727..1fa29539a 100644 --- a/i18n/src/main/res/values-ro/strings.xml +++ b/i18n/src/main/res/values-ro/strings.xml @@ -602,6 +602,7 @@ Ar trebui să păstrați copii ale backupurilor și în alte locuri. Îmbunătățește performanța cititorului Închide + Azi Listă de citit Lista de dorințe Lista completă @@ -648,6 +649,11 @@ Nu s-a putut obține lista de extensii Se instalează extensia… Program instalare + + Ieri + Acum %1$d zile + Acum %1$d zile + Creează dosare în funcție de titlul intrărilor Automat Pornit diff --git a/i18n/src/main/res/values-ru/strings.xml b/i18n/src/main/res/values-ru/strings.xml index 6bbc8fd83..9b9a8e47a 100644 --- a/i18n/src/main/res/values-ru/strings.xml +++ b/i18n/src/main/res/values-ru/strings.xml @@ -604,6 +604,13 @@ Самая высокая Чувствительность скрытия меню при прокрутке Цвета наоборот + + Вчера + %1$d дня назад + %1$d дней назад + %1$d дней назад + + Сегодня Бирюзовая Выполните аутентификацию, чтобы подтвердить изменение По умолчанию diff --git a/i18n/src/main/res/values-sa/strings.xml b/i18n/src/main/res/values-sa/strings.xml index 055b1442b..25834e3e2 100644 --- a/i18n/src/main/res/values-sa/strings.xml +++ b/i18n/src/main/res/values-sa/strings.xml @@ -152,6 +152,11 @@ अभिरक्षणपटलम् अनुप्रयोगाणां परिवर्तने अनुप्रयोगवस्तु वृणोति पटलप्रतिकृतीनां च सृष्टिं निवारयति॥ प्रौढानां कृते एव (१८+) वस्तुमूलानि मूलानां विस्ताराणां च सूचीषु दर्शयतु + अद्य + + ह्यः + द्विदिनपूर्वम् + प्रतिपङ्क्तौ वस्तूनि अनुप्रस्थम् प्रदर्शनम् diff --git a/i18n/src/main/res/values-sc/strings.xml b/i18n/src/main/res/values-sc/strings.xml index 81d71b045..8d4b42c45 100644 --- a/i18n/src/main/res/values-sc/strings.xml +++ b/i18n/src/main/res/values-sc/strings.xml @@ -582,6 +582,11 @@ Sensibilidade pro cuare su menù cun s\'iscurrimentu Atividade in s\'isfundu Furriada + + Eris + %1$d dies a oe + + Oe Birde abba e turchesu Autèntica·ti pro cunfirmare sa modìfica Predefinida diff --git a/i18n/src/main/res/values-sdh/strings.xml b/i18n/src/main/res/values-sdh/strings.xml index b01232095..65edfe421 100644 --- a/i18n/src/main/res/values-sdh/strings.xml +++ b/i18n/src/main/res/values-sdh/strings.xml @@ -168,6 +168,7 @@ سکرین شۆت بلۆکردن و شاردنەوەی ناوەڕۆک، لە کاتی گۆڕین و دەرچوون لە بەرنامە سەرچاوەی سەروو (18) ساڵ پیشاندان لە لیستی سەرچاوە و زیادکراوەکان + ئەمڕۆ شێوازی پیشاندان نوێکردنەوەی تۆماری ڕابردوو…( (%2$d) / (%1$d) ) نەرمە لێدانی پێچەوانە @@ -189,6 +190,10 @@ پاش 1 خولەک پاش %1$s خولەک + + دوێنێ + %1$d ڕۆژ پێش ئێستا + بەدواداچوون زیاد بکە کردنە ناو کۆکراوەکان تکایە مانگا بۆ کۆکراوەکان زیاد بکە پێش کردنی ئەمە diff --git a/i18n/src/main/res/values-sk/strings.xml b/i18n/src/main/res/values-sk/strings.xml index b65c9d614..699246092 100644 --- a/i18n/src/main/res/values-sk/strings.xml +++ b/i18n/src/main/res/values-sk/strings.xml @@ -395,11 +395,17 @@ Preskočiť aktualizáciu záznamov Zobraziť v zoznamoch zdrojov a rozšírení NSFW (18+) zdroje + Dnes Iba na Wi-Fi Obmedzenia: %s S neprečítanými kapitolami Ktoré sa ešte nezačali Toto nastavenie avšak nebráni tomu, aby sa v aplikácii objavil neoficiálny alebo potenciálne nesprávne označený obsah NSFW (18+). + + Včera + Pred %1$d dňami + Pred %1$d dňami + Globálna aktualizácia Automatický obnoviť metadata Pri aktualizácii knižnice skontrolujte nový obal a podrobnosti diff --git a/i18n/src/main/res/values-sq/strings.xml b/i18n/src/main/res/values-sq/strings.xml index 375bc46fa..f992c611b 100644 --- a/i18n/src/main/res/values-sq/strings.xml +++ b/i18n/src/main/res/values-sq/strings.xml @@ -49,6 +49,11 @@ Ekran i sigurt Burimet NSFW (18+) Shfaq në listat e burimeve dhe shtesave + Sot + + Dje + %1$d ditë më parë + Shfaqja Artikuj për rresht Përditësim global diff --git a/i18n/src/main/res/values-sr/strings.xml b/i18n/src/main/res/values-sr/strings.xml index e29bd6f4d..0a66772ff 100644 --- a/i18n/src/main/res/values-sr/strings.xml +++ b/i18n/src/main/res/values-sr/strings.xml @@ -431,6 +431,11 @@ Потпуно црна тема NSFW - извори за одрасле (18+) Показати у листи за изворе и додатке + + Pre %1$d dan + Pre %1$d dana + Pre %1$d dana + Начин читања Инсталер @@ -561,6 +566,7 @@ Грешке Подешавања поглавља + Данас Лево Још немате категорија. Информације о апликацији diff --git a/i18n/src/main/res/values-sv/strings.xml b/i18n/src/main/res/values-sv/strings.xml index b953892dd..ef030d5de 100644 --- a/i18n/src/main/res/values-sv/strings.xml +++ b/i18n/src/main/res/values-sv/strings.xml @@ -582,6 +582,11 @@ Högsta Känslighet för att dölja menyn vid rullning Omvänd + + Igår + För %1$d dagar sedan + + Idag Teal och turkos Utseende Autentisera för att bekräfta ändringen diff --git a/i18n/src/main/res/values-th/strings.xml b/i18n/src/main/res/values-th/strings.xml index 086a071a1..7554082bf 100644 --- a/i18n/src/main/res/values-th/strings.xml +++ b/i18n/src/main/res/values-th/strings.xml @@ -530,6 +530,7 @@ คุณยังไม่มีหมวดหมู่ ยืนยันการเปลี่ยนแปลง + วันนี้ มีตอนที่ยังไม่ได้อ่าน ปิด เปิด @@ -562,6 +563,9 @@ โหลดตัวติดตามใหม่โดยอัตโนมัติ อัปเดตตัวติดตามเมื่ออัปเดตคลัง เริ่มดาวน์โหลดเลย + + %1$d วันที่ผ่านมา + บริการขั้นสูง ควรเก็บสำเนาของข้อมูลสำรองไว้ที่อื่นด้วยเช่นกัน บันทึกบันทึกอย่างละเอียดไปยังบันทึกของระบบ (ลดประสิทธิภาพของแอป) diff --git a/i18n/src/main/res/values-tr/strings.xml b/i18n/src/main/res/values-tr/strings.xml index 399e8f567..f1f3d3e0c 100644 --- a/i18n/src/main/res/values-tr/strings.xml +++ b/i18n/src/main/res/values-tr/strings.xml @@ -582,6 +582,11 @@ En yüksek Kaydırmada komut-seçenek dizelgesini gizleme duyarlılığı Ters Çevrilmiş + + Dün + %1$d gün önce + + Bugün Deniz kökçesi & Türk kökçesi Değişikliği onaylamak için kimlik doğrula Varsayılan diff --git a/i18n/src/main/res/values-uk/strings.xml b/i18n/src/main/res/values-uk/strings.xml index 901359183..e2241a1f7 100644 --- a/i18n/src/main/res/values-uk/strings.xml +++ b/i18n/src/main/res/values-uk/strings.xml @@ -603,6 +603,13 @@ Тема застосунку Розпочати завантаження зараз Інвертовано + + Учора + %1$d днів тому + %1$d днів тому + %1$d днів тому + + Сьогодні Бірюзова Виконайте автентифікацію, щоб підтвердити зміну Типово diff --git a/i18n/src/main/res/values-uz/strings.xml b/i18n/src/main/res/values-uz/strings.xml index ac6548fcb..9b2703dbe 100644 --- a/i18n/src/main/res/values-uz/strings.xml +++ b/i18n/src/main/res/values-uz/strings.xml @@ -178,6 +178,7 @@ Ilova ekrani himoyasi Manbaa va kengaytmalar ro\'yhatida ko\'rsatish Bu, ilovada norasmiy yoki noto\'g\'ri belgilangan kengaytmalardan NSFW (18+) kontent paydo bo\'lishini oldini olmaydi. + Bugun Ko\'rsatish Qismlar soni Qism boshlanmagan @@ -245,6 +246,10 @@ O\'qish boshlanganida o\'qish rejimini birozga ko\'rsatish Qism yakunlangan Kengaytma o\'rnatilmoqda… + + Kecha + %1$d kun oldin + Global yangilanish Metama\'lumotlarni yangilash Istisno qilish: %s diff --git a/i18n/src/main/res/values-vi/strings.xml b/i18n/src/main/res/values-vi/strings.xml index 77b236fec..e37aebf1b 100644 --- a/i18n/src/main/res/values-vi/strings.xml +++ b/i18n/src/main/res/values-vi/strings.xml @@ -613,6 +613,10 @@ Cao Cao nhất Đảo màu + + %1$d ngày trước + + Hôm nay Hỗ trợ dịch thuật Thông tin ứng dụng Cài và chạy Shizuku để sử dụng Shizuku như một trình cài đặt tiện ích mở rộng. diff --git a/i18n/src/main/res/values-zh-rCN/strings.xml b/i18n/src/main/res/values-zh-rCN/strings.xml index a7357a732..2a32f659f 100644 --- a/i18n/src/main/res/values-zh-rCN/strings.xml +++ b/i18n/src/main/res/values-zh-rCN/strings.xml @@ -571,6 +571,10 @@ 最高 滑动时隐藏菜单的灵敏度 反色 + 今天 + + %1$d 天前 + 青色与绿松色 验证以确认更改 默认 diff --git a/i18n/src/main/res/values-zh-rTW/strings.xml b/i18n/src/main/res/values-zh-rTW/strings.xml index 5f19cf8af..71241a535 100644 --- a/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/i18n/src/main/res/values-zh-rTW/strings.xml @@ -574,6 +574,10 @@ 綠松色 驗證以確認變更 外觀 + 今天 + + %1$d 天前 + 預設 平板電腦介面 入門指南 diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt index 6720e74c5..eea05b4ca 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt @@ -70,6 +70,7 @@ fun AdaptiveSheet( val alpha by animateFloatAsState( targetValue = targetAlpha, animationSpec = sheetAnimationSpec, + label = "alpha", ) val internalOnDismissRequest: () -> Unit = { scope.launch { From c8e226acb2ef460f78a298ef44412bb5b2915daf Mon Sep 17 00:00:00 2001 From: arkon Date: Mon, 25 Sep 2023 23:22:16 -0400 Subject: [PATCH 37/59] Tracker-related cleanup --- .../java/eu/kanade/domain/DomainModule.kt | 6 +- .../domain/track/interactor/AddTracks.kt | 47 ++++++++ .../domain/track/interactor/RefreshTracks.kt | 22 ++-- .../SyncChapterProgressWithTrack.kt | 12 +- .../domain/track/interactor/TrackChapter.kt | 15 ++- .../track/service/DelayedTrackingUpdateJob.kt | 6 +- .../domain/track/service/TrackPreferences.kt | 10 +- .../library/LibrarySettingsDialog.kt | 8 +- .../presentation/more/settings/Preference.kt | 8 +- .../more/settings/PreferenceItem.kt | 8 +- .../settings/screen/SettingsAdvancedScreen.kt | 6 +- .../settings/screen/SettingsLibraryScreen.kt | 4 +- .../settings/screen/SettingsTrackingScreen.kt | 102 ++++++++-------- .../widget/TrackingPreferenceWidget.kt | 8 +- .../presentation/track/TrackInfoDialogHome.kt | 22 ++-- ...TrackServiceSearch.kt => TrackerSearch.kt} | 2 +- .../track/components/TrackLogoIcon.kt | 10 +- .../java/eu/kanade/tachiyomi/AppModule.kt | 4 +- .../java/eu/kanade/tachiyomi/Migrations.kt | 10 +- .../data/backup/BackupFileValidator.kt | 6 +- ...bleTrackService.kt => DeletableTracker.kt} | 4 +- ...ncedTrackService.kt => EnhancedTracker.kt} | 15 +-- .../track/{TrackService.kt => Tracker.kt} | 12 +- .../{TrackManager.kt => TrackerManager.kt} | 29 ++--- .../tachiyomi/data/track/anilist/Anilist.kt | 6 +- .../data/track/anilist/AnilistModels.kt | 8 +- .../tachiyomi/data/track/bangumi/Bangumi.kt | 6 +- .../data/track/bangumi/BangumiApi.kt | 9 +- .../tachiyomi/data/track/kavita/Kavita.kt | 36 +++--- .../data/track/kavita/KavitaModels.kt | 4 +- .../tachiyomi/data/track/kitsu/Kitsu.kt | 6 +- .../tachiyomi/data/track/kitsu/KitsuModels.kt | 6 +- .../tachiyomi/data/track/komga/Komga.kt | 10 +- .../tachiyomi/data/track/komga/KomgaApi.kt | 10 +- .../data/track/mangaupdates/MangaUpdates.kt | 6 +- .../data/track/myanimelist/MyAnimeList.kt | 8 +- .../data/track/myanimelist/MyAnimeListApi.kt | 9 +- .../data/track/shikimori/Shikimori.kt | 8 +- .../data/track/shikimori/ShikimoriApi.kt | 11 +- .../tachiyomi/data/track/suwayomi/Suwayomi.kt | 8 +- .../{TachideskApi.kt => SuwayomiApi.kt} | 25 ++-- .../{TachideskDto.kt => SuwayomiModels.kt} | 0 .../browse/migration/search/MigrateDialog.kt | 6 +- .../source/browse/BrowseSourceScreenModel.kt | 36 +----- .../ui/library/LibraryScreenModel.kt | 26 ++-- .../ui/library/LibrarySettingsScreenModel.kt | 8 +- .../kanade/tachiyomi/ui/main/MainActivity.kt | 2 +- .../tachiyomi/ui/manga/MangaScreenModel.kt | 20 +-- .../ui/manga/track/TrackInfoDialog.kt | 114 +++++++++--------- .../tachiyomi/ui/manga/track/TrackItem.kt | 4 +- .../setting/track/BaseOAuthLoginActivity.kt | 4 +- .../ui/setting/track/TrackLoginActivity.kt | 16 +-- .../tachiyomi/ui/stats/StatsScreenModel.kt | 14 +-- i18n/src/main/res/values/strings.xml | 10 +- 54 files changed, 417 insertions(+), 395 deletions(-) create mode 100644 app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt rename app/src/main/java/eu/kanade/domain/{chapter => track}/interactor/SyncChapterProgressWithTrack.kt (83%) rename app/src/main/java/eu/kanade/presentation/track/{TrackServiceSearch.kt => TrackerSearch.kt} (99%) rename app/src/main/java/eu/kanade/tachiyomi/data/track/{DeletableTrackService.kt => DeletableTracker.kt} (56%) rename app/src/main/java/eu/kanade/tachiyomi/data/track/{EnhancedTrackService.kt => EnhancedTracker.kt} (62%) rename app/src/main/java/eu/kanade/tachiyomi/data/track/{TrackService.kt => Tracker.kt} (95%) rename app/src/main/java/eu/kanade/tachiyomi/data/track/{TrackManager.kt => TrackerManager.kt} (51%) rename app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/{TachideskApi.kt => SuwayomiApi.kt} (87%) rename app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/{TachideskDto.kt => SuwayomiModels.kt} (100%) diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index f5e428e8a..4da261de6 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -1,7 +1,6 @@ package eu.kanade.domain import eu.kanade.domain.chapter.interactor.SetReadStatus -import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.download.interactor.DeleteDownload import eu.kanade.domain.extension.interactor.GetExtensionLanguages @@ -16,7 +15,9 @@ import eu.kanade.domain.source.interactor.SetMigrateSorting import eu.kanade.domain.source.interactor.ToggleLanguage import eu.kanade.domain.source.interactor.ToggleSource import eu.kanade.domain.source.interactor.ToggleSourcePin +import eu.kanade.domain.track.interactor.AddTracks import eu.kanade.domain.track.interactor.RefreshTracks +import eu.kanade.domain.track.interactor.SyncChapterProgressWithTrack import eu.kanade.domain.track.interactor.TrackChapter import tachiyomi.data.category.CategoryRepositoryImpl import tachiyomi.data.chapter.ChapterRepositoryImpl @@ -114,11 +115,13 @@ class DomainModule : InjektModule { addSingletonFactory { TrackRepositoryImpl(get()) } addFactory { TrackChapter(get(), get(), get(), get()) } + addFactory { AddTracks(get(), get(), get()) } addFactory { RefreshTracks(get(), get(), get(), get()) } addFactory { DeleteTrack(get()) } addFactory { GetTracksPerManga(get()) } addFactory { GetTracks(get()) } addFactory { InsertTrack(get()) } + addFactory { SyncChapterProgressWithTrack(get(), get(), get()) } addSingletonFactory { ChapterRepositoryImpl(get()) } addFactory { GetChapter(get()) } @@ -127,7 +130,6 @@ class DomainModule : InjektModule { addFactory { SetReadStatus(get(), get(), get(), get()) } addFactory { ShouldUpdateDbChapter() } addFactory { SyncChaptersWithSource(get(), get(), get(), get(), get(), get(), get()) } - addFactory { SyncChapterProgressWithTrack(get(), get(), get()) } addSingletonFactory { HistoryRepositoryImpl(get()) } addFactory { GetHistory(get()) } diff --git a/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt b/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt new file mode 100644 index 000000000..5a56889fb --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt @@ -0,0 +1,47 @@ +package eu.kanade.domain.track.interactor + +import eu.kanade.domain.track.model.toDomainTrack +import eu.kanade.tachiyomi.data.track.EnhancedTracker +import eu.kanade.tachiyomi.data.track.Tracker +import eu.kanade.tachiyomi.source.Source +import logcat.LogPriority +import tachiyomi.core.util.lang.withNonCancellableContext +import tachiyomi.core.util.system.logcat +import tachiyomi.domain.manga.model.Manga +import tachiyomi.domain.track.interactor.GetTracks +import tachiyomi.domain.track.interactor.InsertTrack + +class AddTracks( + private val getTracks: GetTracks, + private val insertTrack: InsertTrack, + private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack, +) { + + suspend fun bindEnhancedTracks(manga: Manga, source: Source) { + withNonCancellableContext { + getTracks.await(manga.id) + .filterIsInstance() + .filter { it.accept(source) } + .forEach { service -> + try { + service.match(manga)?.let { track -> + track.manga_id = manga.id + (service as Tracker).bind(track) + insertTrack.await(track.toDomainTrack()!!) + + syncChapterProgressWithTrack.await( + manga.id, + track.toDomainTrack()!!, + service, + ) + } + } catch (e: Exception) { + logcat( + LogPriority.WARN, + e, + ) { "Could not match manga: ${manga.title} with service $service" } + } + } + } + } +} diff --git a/app/src/main/java/eu/kanade/domain/track/interactor/RefreshTracks.kt b/app/src/main/java/eu/kanade/domain/track/interactor/RefreshTracks.kt index 87b7c8d99..8c8952304 100644 --- a/app/src/main/java/eu/kanade/domain/track/interactor/RefreshTracks.kt +++ b/app/src/main/java/eu/kanade/domain/track/interactor/RefreshTracks.kt @@ -1,10 +1,9 @@ package eu.kanade.domain.track.interactor -import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack import eu.kanade.domain.track.model.toDbTrack import eu.kanade.domain.track.model.toDomainTrack -import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.Tracker +import eu.kanade.tachiyomi.data.track.TrackerManager import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.supervisorScope @@ -13,7 +12,7 @@ import tachiyomi.domain.track.interactor.InsertTrack class RefreshTracks( private val getTracks: GetTracks, - private val trackManager: TrackManager, + private val trackerManager: TrackerManager, private val insertTrack: InsertTrack, private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack, ) { @@ -23,18 +22,17 @@ class RefreshTracks( * * @return Failed updates. */ - suspend fun await(mangaId: Long): List> { + suspend fun await(mangaId: Long): List> { return supervisorScope { return@supervisorScope getTracks.await(mangaId) - .map { track -> + .map { it to trackerManager.get(it.syncId) } + .filter { (_, service) -> service?.isLoggedIn == true } + .map { (track, service) -> async { - val service = trackManager.getService(track.syncId) return@async try { - if (service?.isLoggedIn == true) { - val updatedTrack = service.refresh(track.toDbTrack()) - insertTrack.await(updatedTrack.toDomainTrack()!!) - syncChapterProgressWithTrack.await(mangaId, track, service) - } + val updatedTrack = service!!.refresh(track.toDbTrack()) + insertTrack.await(updatedTrack.toDomainTrack()!!) + syncChapterProgressWithTrack.await(mangaId, track, service) null } catch (e: Throwable) { service to e diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChapterProgressWithTrack.kt b/app/src/main/java/eu/kanade/domain/track/interactor/SyncChapterProgressWithTrack.kt similarity index 83% rename from app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChapterProgressWithTrack.kt rename to app/src/main/java/eu/kanade/domain/track/interactor/SyncChapterProgressWithTrack.kt index 86862504c..dcb95ff26 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChapterProgressWithTrack.kt +++ b/app/src/main/java/eu/kanade/domain/track/interactor/SyncChapterProgressWithTrack.kt @@ -1,8 +1,8 @@ -package eu.kanade.domain.chapter.interactor +package eu.kanade.domain.track.interactor import eu.kanade.domain.track.model.toDbTrack -import eu.kanade.tachiyomi.data.track.EnhancedTrackService -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.EnhancedTracker +import eu.kanade.tachiyomi.data.track.Tracker import logcat.LogPriority import tachiyomi.core.util.system.logcat import tachiyomi.domain.chapter.interactor.GetChapterByMangaId @@ -20,9 +20,9 @@ class SyncChapterProgressWithTrack( suspend fun await( mangaId: Long, remoteTrack: Track, - service: TrackService, + tracker: Tracker, ) { - if (service !is EnhancedTrackService) { + if (tracker !is EnhancedTracker) { return } @@ -39,7 +39,7 @@ class SyncChapterProgressWithTrack( val updatedTrack = remoteTrack.copy(lastChapterRead = localLastRead.toDouble()) try { - service.update(updatedTrack.toDbTrack()) + tracker.update(updatedTrack.toDbTrack()) updateChapter.awaitAll(chapterUpdates) insertTrack.await(updatedTrack) } catch (e: Throwable) { diff --git a/app/src/main/java/eu/kanade/domain/track/interactor/TrackChapter.kt b/app/src/main/java/eu/kanade/domain/track/interactor/TrackChapter.kt index 96f2f6ca4..fa6245f22 100644 --- a/app/src/main/java/eu/kanade/domain/track/interactor/TrackChapter.kt +++ b/app/src/main/java/eu/kanade/domain/track/interactor/TrackChapter.kt @@ -4,30 +4,29 @@ import android.content.Context import eu.kanade.domain.track.model.toDbTrack import eu.kanade.domain.track.service.DelayedTrackingUpdateJob import eu.kanade.domain.track.store.DelayedTrackingStore -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.coroutineScope import logcat.LogPriority -import tachiyomi.core.util.lang.launchNonCancellable +import tachiyomi.core.util.lang.withNonCancellableContext import tachiyomi.core.util.system.logcat import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.InsertTrack class TrackChapter( private val getTracks: GetTracks, - private val trackManager: TrackManager, + private val trackerManager: TrackerManager, private val insertTrack: InsertTrack, private val delayedTrackingStore: DelayedTrackingStore, ) { - suspend fun await(context: Context, mangaId: Long, chapterNumber: Double) = coroutineScope { - launchNonCancellable { + suspend fun await(context: Context, mangaId: Long, chapterNumber: Double) { + withNonCancellableContext { val tracks = getTracks.await(mangaId) - if (tracks.isEmpty()) return@launchNonCancellable + if (tracks.isEmpty()) return@withNonCancellableContext tracks.mapNotNull { track -> - val service = trackManager.getService(track.syncId) + val service = trackerManager.get(track.syncId) if (service == null || !service.isLoggedIn || chapterNumber <= track.lastChapterRead) { return@mapNotNull null } diff --git a/app/src/main/java/eu/kanade/domain/track/service/DelayedTrackingUpdateJob.kt b/app/src/main/java/eu/kanade/domain/track/service/DelayedTrackingUpdateJob.kt index 0273e0fdc..f578bd600 100644 --- a/app/src/main/java/eu/kanade/domain/track/service/DelayedTrackingUpdateJob.kt +++ b/app/src/main/java/eu/kanade/domain/track/service/DelayedTrackingUpdateJob.kt @@ -10,7 +10,7 @@ import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkerParameters import eu.kanade.domain.track.model.toDbTrack import eu.kanade.domain.track.store.DelayedTrackingStore -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.util.system.workManager import logcat.LogPriority import tachiyomi.core.util.lang.withIOContext @@ -33,7 +33,7 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters) val getTracks = Injekt.get() val insertTrack = Injekt.get() - val trackManager = Injekt.get() + val trackerManager = Injekt.get() val delayedTrackingStore = Injekt.get() withIOContext { @@ -47,7 +47,7 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters) } .forEach { track -> try { - val service = trackManager.getService(track.syncId) + val service = trackerManager.get(track.syncId) if (service != null && service.isLoggedIn) { logcat(LogPriority.DEBUG) { "Updating delayed track item: ${track.id}, last chapter read: ${track.lastChapterRead}" } service.update(track.toDbTrack(), true) diff --git a/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt b/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt index 2ddba51e0..418d794b9 100644 --- a/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt +++ b/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt @@ -1,6 +1,6 @@ package eu.kanade.domain.track.service -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.anilist.Anilist import tachiyomi.core.preference.PreferenceStore @@ -8,16 +8,16 @@ class TrackPreferences( private val preferenceStore: PreferenceStore, ) { - fun trackUsername(sync: TrackService) = preferenceStore.getString(trackUsername(sync.id), "") + fun trackUsername(sync: Tracker) = preferenceStore.getString(trackUsername(sync.id), "") - fun trackPassword(sync: TrackService) = preferenceStore.getString(trackPassword(sync.id), "") + fun trackPassword(sync: Tracker) = preferenceStore.getString(trackPassword(sync.id), "") - fun setTrackCredentials(sync: TrackService, username: String, password: String) { + fun setCredentials(sync: Tracker, username: String, password: String) { trackUsername(sync).set(username) trackPassword(sync).set(password) } - fun trackToken(sync: TrackService) = preferenceStore.getString(trackToken(sync.id), "") + fun trackToken(sync: Tracker) = preferenceStore.getString(trackToken(sync.id), "") fun anilistScoreType() = preferenceStore.getString("anilist_score_type", Anilist.POINT_10) diff --git a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt index 0c8a80217..6d7882f43 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -108,13 +108,13 @@ private fun ColumnScope.FilterPage( onClick = { screenModel.toggleFilter(LibraryPreferences::filterCompleted) }, ) - val trackServices = remember { screenModel.trackServices } - when (trackServices.size) { + val trackers = remember { screenModel.trackers } + when (trackers.size) { 0 -> { // No trackers } 1 -> { - val service = trackServices[0] + val service = trackers[0] val filterTracker by screenModel.libraryPreferences.filterTracking(service.id.toInt()).collectAsState() TriStateItem( label = stringResource(R.string.action_filter_tracked), @@ -124,7 +124,7 @@ private fun ColumnScope.FilterPage( } else -> { HeadingItem(R.string.action_filter_tracked) - trackServices.map { service -> + trackers.map { service -> val filterTracker by screenModel.libraryPreferences.filterTracking(service.id.toInt()).collectAsState() TriStateItem( label = service.name, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt b/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt index fa25ff184..c852e03a3 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt @@ -5,7 +5,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.Tracker import tachiyomi.core.preference.Preference as PreferenceData sealed class Preference { @@ -132,10 +132,10 @@ sealed class Preference { ) : PreferenceItem() /** - * A [PreferenceItem] for individual tracking service. + * A [PreferenceItem] for individual tracker. */ - data class TrackingPreference( - val service: TrackService, + data class TrackerPreference( + val tracker: Tracker, override val title: String, val login: () -> Unit, val logout: () -> Unit, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt index 940a48225..b68f17fcd 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt @@ -156,13 +156,13 @@ internal fun PreferenceItem( }, ) } - is Preference.PreferenceItem.TrackingPreference -> { + is Preference.PreferenceItem.TrackerPreference -> { val uName by Injekt.get() - .getString(TrackPreferences.trackUsername(item.service.id)) + .getString(TrackPreferences.trackUsername(item.tracker.id)) .collectAsState() - item.service.run { + item.tracker.run { TrackingPreferenceWidget( - service = this, + tracker = this, checked = uName.isNotEmpty(), onClick = { if (isLoggedIn) item.logout() else item.login() }, ) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt index cd600969c..cad067a98 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt @@ -34,7 +34,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.data.download.DownloadCache import eu.kanade.tachiyomi.data.library.LibraryUpdateJob -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.network.PREF_DOH_360 @@ -328,7 +328,7 @@ object SettingsAdvancedScreen : SearchableSettings { private fun getLibraryGroup(): Preference.PreferenceGroup { val scope = rememberCoroutineScope() val context = LocalContext.current - val trackManager = remember { Injekt.get() } + val trackerManager = remember { Injekt.get() } return Preference.PreferenceGroup( title = stringResource(R.string.label_library), @@ -340,7 +340,7 @@ object SettingsAdvancedScreen : SearchableSettings { Preference.PreferenceItem.TextPreference( title = stringResource(R.string.pref_refresh_library_tracking), subtitle = stringResource(R.string.pref_refresh_library_tracking_summary), - enabled = trackManager.hasLoggedServices(), + enabled = trackerManager.hasLoggedIn(), onClick = { LibraryUpdateJob.startNow(context, target = LibraryUpdateJob.Target.TRACKING) }, ), Preference.PreferenceItem.TextPreference( diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt index 35552e225..0e71d4cdb 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt @@ -23,7 +23,7 @@ import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.more.settings.widget.TriStateListDialog import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.library.LibraryUpdateJob -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.ui.category.CategoryScreen import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -199,7 +199,7 @@ object SettingsLibraryScreen : SearchableSettings { ), Preference.PreferenceItem.SwitchPreference( pref = libraryPreferences.autoUpdateTrackers(), - enabled = Injekt.get().hasLoggedServices(), + enabled = Injekt.get().hasLoggedIn(), title = stringResource(R.string.pref_library_update_refresh_trackers), subtitle = stringResource(R.string.pref_library_update_refresh_trackers_summary), ), diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt index d57034536..655d79cc2 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt @@ -44,9 +44,9 @@ import androidx.compose.ui.unit.dp import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.presentation.more.settings.Preference import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.track.EnhancedTrackService -import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.EnhancedTracker +import eu.kanade.tachiyomi.data.track.Tracker +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.anilist.AnilistApi import eu.kanade.tachiyomi.data.track.bangumi.BangumiApi import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeListApi @@ -82,7 +82,7 @@ object SettingsTrackingScreen : SearchableSettings { override fun getPreferences(): List { val context = LocalContext.current val trackPreferences = remember { Injekt.get() } - val trackManager = remember { Injekt.get() } + val trackerManager = remember { Injekt.get() } val sourceManager = remember { Injekt.get() } var dialog by remember { mutableStateOf(null) } @@ -90,24 +90,24 @@ object SettingsTrackingScreen : SearchableSettings { when (this) { is LoginDialog -> { TrackingLoginDialog( - service = service, + tracker = tracker, uNameStringRes = uNameStringRes, onDismissRequest = { dialog = null }, ) } is LogoutDialog -> { TrackingLogoutDialog( - service = service, + tracker = tracker, onDismissRequest = { dialog = null }, ) } } } - val enhancedTrackers = trackManager.services - .filter { it is EnhancedTrackService } + val enhancedTrackers = trackerManager.trackers + .filter { it is EnhancedTracker } .partition { service -> - val acceptedSources = (service as EnhancedTrackService).getAcceptedSources() + val acceptedSources = (service as EnhancedTracker).getAcceptedSources() sourceManager.getCatalogueSources().any { it::class.qualifiedName in acceptedSources } } var enhancedTrackerInfo = stringResource(R.string.enhanced_tracking_info) @@ -127,41 +127,41 @@ object SettingsTrackingScreen : SearchableSettings { Preference.PreferenceGroup( title = stringResource(R.string.services), preferenceItems = listOf( - Preference.PreferenceItem.TrackingPreference( - title = trackManager.myAnimeList.name, - service = trackManager.myAnimeList, + Preference.PreferenceItem.TrackerPreference( + title = trackerManager.myAnimeList.name, + tracker = trackerManager.myAnimeList, login = { context.openInBrowser(MyAnimeListApi.authUrl(), forceDefaultBrowser = true) }, - logout = { dialog = LogoutDialog(trackManager.myAnimeList) }, + logout = { dialog = LogoutDialog(trackerManager.myAnimeList) }, ), - Preference.PreferenceItem.TrackingPreference( - title = trackManager.aniList.name, - service = trackManager.aniList, + Preference.PreferenceItem.TrackerPreference( + title = trackerManager.aniList.name, + tracker = trackerManager.aniList, login = { context.openInBrowser(AnilistApi.authUrl(), forceDefaultBrowser = true) }, - logout = { dialog = LogoutDialog(trackManager.aniList) }, + logout = { dialog = LogoutDialog(trackerManager.aniList) }, ), - Preference.PreferenceItem.TrackingPreference( - title = trackManager.kitsu.name, - service = trackManager.kitsu, - login = { dialog = LoginDialog(trackManager.kitsu, R.string.email) }, - logout = { dialog = LogoutDialog(trackManager.kitsu) }, + Preference.PreferenceItem.TrackerPreference( + title = trackerManager.kitsu.name, + tracker = trackerManager.kitsu, + login = { dialog = LoginDialog(trackerManager.kitsu, R.string.email) }, + logout = { dialog = LogoutDialog(trackerManager.kitsu) }, ), - Preference.PreferenceItem.TrackingPreference( - title = trackManager.mangaUpdates.name, - service = trackManager.mangaUpdates, - login = { dialog = LoginDialog(trackManager.mangaUpdates, R.string.username) }, - logout = { dialog = LogoutDialog(trackManager.mangaUpdates) }, + Preference.PreferenceItem.TrackerPreference( + title = trackerManager.mangaUpdates.name, + tracker = trackerManager.mangaUpdates, + login = { dialog = LoginDialog(trackerManager.mangaUpdates, R.string.username) }, + logout = { dialog = LogoutDialog(trackerManager.mangaUpdates) }, ), - Preference.PreferenceItem.TrackingPreference( - title = trackManager.shikimori.name, - service = trackManager.shikimori, + Preference.PreferenceItem.TrackerPreference( + title = trackerManager.shikimori.name, + tracker = trackerManager.shikimori, login = { context.openInBrowser(ShikimoriApi.authUrl(), forceDefaultBrowser = true) }, - logout = { dialog = LogoutDialog(trackManager.shikimori) }, + logout = { dialog = LogoutDialog(trackerManager.shikimori) }, ), - Preference.PreferenceItem.TrackingPreference( - title = trackManager.bangumi.name, - service = trackManager.bangumi, + Preference.PreferenceItem.TrackerPreference( + title = trackerManager.bangumi.name, + tracker = trackerManager.bangumi, login = { context.openInBrowser(BangumiApi.authUrl(), forceDefaultBrowser = true) }, - logout = { dialog = LogoutDialog(trackManager.bangumi) }, + logout = { dialog = LogoutDialog(trackerManager.bangumi) }, ), Preference.PreferenceItem.InfoPreference(stringResource(R.string.tracking_info)), ), @@ -170,10 +170,10 @@ object SettingsTrackingScreen : SearchableSettings { title = stringResource(R.string.enhanced_services), preferenceItems = enhancedTrackers.first .map { service -> - Preference.PreferenceItem.TrackingPreference( + Preference.PreferenceItem.TrackerPreference( title = service.name, - service = service, - login = { (service as EnhancedTrackService).loginNoop() }, + tracker = service, + login = { (service as EnhancedTracker).loginNoop() }, logout = service::logout, ) } + listOf(Preference.PreferenceItem.InfoPreference(enhancedTrackerInfo)), @@ -183,15 +183,15 @@ object SettingsTrackingScreen : SearchableSettings { @Composable private fun TrackingLoginDialog( - service: TrackService, + tracker: Tracker, @StringRes uNameStringRes: Int, onDismissRequest: () -> Unit, ) { val context = LocalContext.current val scope = rememberCoroutineScope() - var username by remember { mutableStateOf(TextFieldValue(service.getUsername())) } - var password by remember { mutableStateOf(TextFieldValue(service.getPassword())) } + var username by remember { mutableStateOf(TextFieldValue(tracker.getUsername())) } + var password by remember { mutableStateOf(TextFieldValue(tracker.getPassword())) } var processing by remember { mutableStateOf(false) } var inputError by remember { mutableStateOf(false) } @@ -200,7 +200,7 @@ object SettingsTrackingScreen : SearchableSettings { title = { Row(verticalAlignment = Alignment.CenterVertically) { Text( - text = stringResource(R.string.login_title, service.name), + text = stringResource(R.string.login_title, tracker.name), modifier = Modifier.weight(1f), ) IconButton(onClick = onDismissRequest) { @@ -264,7 +264,7 @@ object SettingsTrackingScreen : SearchableSettings { processing = true val result = checkLogin( context = context, - service = service, + tracker = tracker, username = username.text, password = password.text, ) @@ -283,16 +283,16 @@ object SettingsTrackingScreen : SearchableSettings { private suspend fun checkLogin( context: Context, - service: TrackService, + tracker: Tracker, username: String, password: String, ): Boolean { return try { - service.login(username, password) + tracker.login(username, password) withUIContext { context.toast(R.string.login_success) } true } catch (e: Throwable) { - service.logout() + tracker.logout() withUIContext { context.toast(e.message.toString()) } false } @@ -300,7 +300,7 @@ object SettingsTrackingScreen : SearchableSettings { @Composable private fun TrackingLogoutDialog( - service: TrackService, + tracker: Tracker, onDismissRequest: () -> Unit, ) { val context = LocalContext.current @@ -308,7 +308,7 @@ object SettingsTrackingScreen : SearchableSettings { onDismissRequest = onDismissRequest, title = { Text( - text = stringResource(R.string.logout_title, service.name), + text = stringResource(R.string.logout_title, tracker.name), textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth(), ) @@ -324,7 +324,7 @@ object SettingsTrackingScreen : SearchableSettings { Button( modifier = Modifier.weight(1f), onClick = { - service.logout() + tracker.logout() onDismissRequest() context.toast(R.string.logout_success) }, @@ -342,10 +342,10 @@ object SettingsTrackingScreen : SearchableSettings { } private data class LoginDialog( - val service: TrackService, + val tracker: Tracker, @StringRes val uNameStringRes: Int, ) private data class LogoutDialog( - val service: TrackService, + val tracker: Tracker, ) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt index e0c34fbc4..d8544d156 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt @@ -20,12 +20,12 @@ import androidx.compose.ui.unit.dp import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted import eu.kanade.presentation.track.components.TrackLogoIcon import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.Tracker @Composable fun TrackingPreferenceWidget( modifier: Modifier = Modifier, - service: TrackService, + tracker: Tracker, checked: Boolean, onClick: (() -> Unit)? = null, ) { @@ -38,9 +38,9 @@ fun TrackingPreferenceWidget( .padding(horizontal = PrefsHorizontalPadding, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically, ) { - TrackLogoIcon(service) + TrackLogoIcon(tracker) Text( - text = service.name, + text = tracker.name, modifier = Modifier .weight(1f) .padding(horizontal = 16.dp), diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt index d9a899d5d..bf7860147 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt @@ -49,7 +49,7 @@ import eu.kanade.domain.track.model.toDbTrack import eu.kanade.presentation.components.DropdownMenu import eu.kanade.presentation.track.components.TrackLogoIcon import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.ui.manga.track.TrackItem import eu.kanade.tachiyomi.util.system.copyToClipboard import java.text.DateFormat @@ -80,12 +80,12 @@ fun TrackInfoDialogHome( ) { trackItems.forEach { item -> if (item.track != null) { - val supportsScoring = item.service.getScoreList().isNotEmpty() - val supportsReadingDates = item.service.supportsReadingDates + val supportsScoring = item.tracker.getScoreList().isNotEmpty() + val supportsReadingDates = item.tracker.supportsReadingDates TrackInfoItem( title = item.track.title, - service = item.service, - status = item.service.getStatus(item.track.status.toInt()), + tracker = item.tracker, + status = item.tracker.getStatus(item.track.status.toInt()), onStatusClick = { onStatusClick(item) }, chapters = "${item.track.lastChapterRead.toInt()}".let { val totalChapters = item.track.totalChapters @@ -97,7 +97,7 @@ fun TrackInfoDialogHome( } }, onChaptersClick = { onChapterClick(item) }, - score = item.service.displayScore(item.track.toDbTrack()) + score = item.tracker.displayScore(item.track.toDbTrack()) .takeIf { supportsScoring && item.track.score != 0.0 }, onScoreClick = { onScoreClick(item) } .takeIf { supportsScoring }, @@ -115,7 +115,7 @@ fun TrackInfoDialogHome( ) } else { TrackInfoItemEmpty( - service = item.service, + tracker = item.tracker, onNewSearch = { onNewSearch(item) }, ) } @@ -126,7 +126,7 @@ fun TrackInfoDialogHome( @Composable private fun TrackInfoItem( title: String, - service: TrackService, + tracker: Tracker, @StringRes status: Int?, onStatusClick: () -> Unit, chapters: String, @@ -147,7 +147,7 @@ private fun TrackInfoItem( verticalAlignment = Alignment.CenterVertically, ) { TrackLogoIcon( - service = service, + tracker = tracker, onClick = onOpenInBrowser, ) Box( @@ -260,13 +260,13 @@ private fun TrackDetailsItem( @Composable private fun TrackInfoItemEmpty( - service: TrackService, + tracker: Tracker, onNewSearch: () -> Unit, ) { Row( verticalAlignment = Alignment.CenterVertically, ) { - TrackLogoIcon(service) + TrackLogoIcon(tracker) TextButton( onClick = onNewSearch, modifier = Modifier diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackServiceSearch.kt b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt similarity index 99% rename from app/src/main/java/eu/kanade/presentation/track/TrackServiceSearch.kt rename to app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt index 1ac38ecf0..c2b951453 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackServiceSearch.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt @@ -70,7 +70,7 @@ import tachiyomi.presentation.core.util.runOnEnterKeyPressed import tachiyomi.presentation.core.util.secondaryItemAlpha @Composable -fun TrackServiceSearch( +fun TrackerSearch( query: TextFieldValue, onQueryChange: (TextFieldValue) -> Unit, onDispatchQuery: () -> Unit, diff --git a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt index 44d98cbd2..52bf66575 100644 --- a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt +++ b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt @@ -12,12 +12,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.Tracker import tachiyomi.presentation.core.util.clickableNoIndication @Composable fun TrackLogoIcon( - service: TrackService, + tracker: Tracker, onClick: (() -> Unit)? = null, ) { val modifier = if (onClick != null) { @@ -29,13 +29,13 @@ fun TrackLogoIcon( Box( modifier = modifier .size(48.dp) - .background(color = Color(service.getLogoColor()), shape = MaterialTheme.shapes.medium) + .background(color = Color(tracker.getLogoColor()), shape = MaterialTheme.shapes.medium) .padding(4.dp), contentAlignment = Alignment.Center, ) { Image( - painter = painterResource(service.getLogo()), - contentDescription = service.name, + painter = painterResource(tracker.getLogo()), + contentDescription = tracker.name, ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt b/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt index 481ff079a..51bd28098 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt @@ -19,7 +19,7 @@ import eu.kanade.tachiyomi.data.download.DownloadCache import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadProvider import eu.kanade.tachiyomi.data.saver.ImageSaver -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.network.JavaScriptEngine import eu.kanade.tachiyomi.network.NetworkHelper @@ -132,7 +132,7 @@ class AppModule(val app: Application) : InjektModule { addSingletonFactory { DownloadManager(app) } addSingletonFactory { DownloadCache(app) } - addSingletonFactory { TrackManager(app) } + addSingletonFactory { TrackerManager() } addSingletonFactory { DelayedTrackingStore(app) } addSingletonFactory { ImageSaver(app) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index 3c15c913d..c3b4db069 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -9,7 +9,7 @@ import eu.kanade.domain.ui.UiPreferences import eu.kanade.tachiyomi.core.security.SecurityPreferences import eu.kanade.tachiyomi.data.backup.BackupCreateJob import eu.kanade.tachiyomi.data.library.LibraryUpdateJob -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE import eu.kanade.tachiyomi.ui.reader.setting.OrientationType @@ -47,7 +47,7 @@ object Migrations { libraryPreferences: LibraryPreferences, readerPreferences: ReaderPreferences, backupPreferences: BackupPreferences, - trackManager: TrackManager, + trackerManager: TrackerManager, ): Boolean { val lastVersionCode = preferenceStore.getInt("last_version_code", 0) val oldVersion = lastVersionCode.get() @@ -135,8 +135,8 @@ object Migrations { // Force MAL log out due to login flow change // v52: switched from scraping to WebView // v53: switched from WebView to OAuth - if (trackManager.myAnimeList.isLoggedIn) { - trackManager.myAnimeList.logout() + if (trackerManager.myAnimeList.isLoggedIn) { + trackerManager.myAnimeList.logout() context.toast(R.string.myanimelist_relogin) } } @@ -342,7 +342,7 @@ object Migrations { "pref_filter_library_started", "pref_filter_library_bookmarked", "pref_filter_library_completed", - ) + trackManager.services.map { "pref_filter_library_tracked_${it.id}" } + ) + trackerManager.trackers.map { "pref_filter_library_tracked_${it.id}" } prefKeys.forEach { key -> val pref = preferenceStore.getInt(key, 0) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt index 0fe9ddff9..ea8f3c9ea 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt @@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.data.backup import android.content.Context import android.net.Uri import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.util.BackupUtil import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.Injekt @@ -11,7 +11,7 @@ import uy.kohesive.injekt.api.get class BackupFileValidator( private val sourceManager: SourceManager = Injekt.get(), - private val trackManager: TrackManager = Injekt.get(), + private val trackerManager: TrackerManager = Injekt.get(), ) { /** @@ -50,7 +50,7 @@ class BackupFileValidator( .map { it.syncId } .distinct() val missingTrackers = trackers - .mapNotNull { trackManager.getService(it.toLong()) } + .mapNotNull { trackerManager.get(it.toLong()) } .filter { !it.isLoggedIn } .map { it.name } .sorted() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/DeletableTrackService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/DeletableTracker.kt similarity index 56% rename from app/src/main/java/eu/kanade/tachiyomi/data/track/DeletableTrackService.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/track/DeletableTracker.kt index 7f1494707..c61c55e78 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/DeletableTrackService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/DeletableTracker.kt @@ -3,9 +3,9 @@ package eu.kanade.tachiyomi.data.track import eu.kanade.tachiyomi.data.database.models.Track /** - * For track services api that support deleting a manga entry for a user's list + * Tracker that support deleting am entry from a user's list. */ -interface DeletableTrackService { +interface DeletableTracker { suspend fun delete(track: Track): Track } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/EnhancedTrackService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/EnhancedTracker.kt similarity index 62% rename from app/src/main/java/eu/kanade/tachiyomi/data/track/EnhancedTrackService.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/track/EnhancedTracker.kt index 75245cf80..a501cded8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/EnhancedTrackService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/EnhancedTracker.kt @@ -6,31 +6,32 @@ import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.track.model.Track /** - * An Enhanced Track Service will never prompt the user to match a manga with the remote. - * It is expected that such Track Service can only work with specific sources and unique IDs. + * A tracker that will never prompt the user to manually bind an entry. + * It is expected that such tracker can only work with specific sources and unique IDs. */ -interface EnhancedTrackService { +interface EnhancedTracker { + /** - * This TrackService will only work with the sources that are accepted by this filter function. + * This tracker will only work with the sources that are accepted by this filter function. */ fun accept(source: Source): Boolean { return source::class.qualifiedName in getAcceptedSources() } /** - * Fully qualified source classes that this track service is compatible with. + * Fully qualified source classes that this tracker is compatible with. */ fun getAcceptedSources(): List fun loginNoop() /** - * match is similar to TrackService.search, but only return zero or one match. + * Similar to [Tracker].search, but only returns zero or one match. */ suspend fun match(manga: Manga): TrackSearch? /** - * Checks whether the provided source/track/manga triplet is from this TrackService + * Checks whether the provided source/track/manga triplet is from this [Tracker] */ fun isTrackFrom(track: Track, manga: Manga, source: Source?): Boolean diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt similarity index 95% rename from app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt index e30100e29..490ea0e96 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt @@ -5,7 +5,7 @@ import androidx.annotation.CallSuper import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.annotation.StringRes -import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack +import eu.kanade.domain.track.interactor.SyncChapterProgressWithTrack import eu.kanade.domain.track.model.toDbTrack import eu.kanade.domain.track.model.toDomainTrack import eu.kanade.domain.track.service.TrackPreferences @@ -28,7 +28,7 @@ import uy.kohesive.injekt.injectLazy import java.time.ZoneOffset import tachiyomi.domain.track.model.Track as DomainTrack -abstract class TrackService(val id: Long, val name: String) { +abstract class Tracker(val id: Long, val name: String) { val trackPreferences: TrackPreferences by injectLazy() val networkService: NetworkHelper by injectLazy() @@ -83,7 +83,7 @@ abstract class TrackService(val id: Long, val name: String) { @CallSuper open fun logout() { - trackPreferences.setTrackCredentials(this, "", "") + trackPreferences.setCredentials(this, "", "") } open val isLoggedIn: Boolean @@ -95,7 +95,7 @@ abstract class TrackService(val id: Long, val name: String) { fun getPassword() = trackPreferences.trackPassword(this).get() fun saveCredentials(username: String, password: String) { - trackPreferences.setTrackCredentials(this, username, password) + trackPreferences.setCredentials(this, username, password) } // TODO: move this to an interactor, and update all trackers based on common data @@ -111,7 +111,7 @@ abstract class TrackService(val id: Long, val name: String) { insertTrack.await(track) - // TODO: merge into SyncChaptersWithTrackServiceTwoWay? + // TODO: merge into [SyncChapterProgressWithTrack]? // Update chapter progress if newer chapters marked read locally if (hasReadChapters) { val latestLocalReadChapterNumber = allChapters @@ -143,7 +143,7 @@ abstract class TrackService(val id: Long, val name: String) { } } - syncChapterProgressWithTrack.await(mangaId, track, this@TrackService) + syncChapterProgressWithTrack.await(mangaId, track, this@Tracker) } } catch (e: Throwable) { withUIContext { Injekt.get().toast(e.message) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt similarity index 51% rename from app/src/main/java/eu/kanade/tachiyomi/data/track/TrackManager.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt index c6d62c382..3943537e2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt @@ -1,6 +1,5 @@ package eu.kanade.tachiyomi.data.track -import android.content.Context import eu.kanade.tachiyomi.data.track.anilist.Anilist import eu.kanade.tachiyomi.data.track.bangumi.Bangumi import eu.kanade.tachiyomi.data.track.kavita.Kavita @@ -11,33 +10,27 @@ import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeList import eu.kanade.tachiyomi.data.track.shikimori.Shikimori import eu.kanade.tachiyomi.data.track.suwayomi.Suwayomi -class TrackManager(context: Context) { +class TrackerManager { companion object { - const val MYANIMELIST = 1L const val ANILIST = 2L const val KITSU = 3L - const val SHIKIMORI = 4L - const val BANGUMI = 5L - const val KOMGA = 6L - const val MANGA_UPDATES = 7L const val KAVITA = 8L - const val SUWAYOMI = 9L } - val myAnimeList = MyAnimeList(MYANIMELIST) + val myAnimeList = MyAnimeList(1L) val aniList = Anilist(ANILIST) val kitsu = Kitsu(KITSU) - val shikimori = Shikimori(SHIKIMORI) - val bangumi = Bangumi(BANGUMI) - val komga = Komga(KOMGA) - val mangaUpdates = MangaUpdates(MANGA_UPDATES) - val kavita = Kavita(context, KAVITA) - val suwayomi = Suwayomi(SUWAYOMI) + val shikimori = Shikimori(4L) + val bangumi = Bangumi(5L) + val komga = Komga(6L) + val mangaUpdates = MangaUpdates(7L) + val kavita = Kavita(KAVITA) + val suwayomi = Suwayomi(9L) - val services = listOf(myAnimeList, aniList, kitsu, shikimori, bangumi, komga, mangaUpdates, kavita, suwayomi) + val trackers = listOf(myAnimeList, aniList, kitsu, shikimori, bangumi, komga, mangaUpdates, kavita, suwayomi) - fun getService(id: Long) = services.find { it.id == id } + fun get(id: Long) = trackers.find { it.id == id } - fun hasLoggedServices() = services.any { it.isLoggedIn } + fun hasLoggedIn() = trackers.any { it.isLoggedIn } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt index c6365106e..3ecf9119d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt @@ -4,15 +4,15 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.DeletableTrackService -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.DeletableTracker +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy import tachiyomi.domain.track.model.Track as DomainTrack -class Anilist(id: Long) : TrackService(id, "AniList"), DeletableTrackService { +class Anilist(id: Long) : Tracker(id, "AniList"), DeletableTracker { companion object { const val READING = 1 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt index 0e39d680f..46de5e735 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.data.track.anilist import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.Serializable import uy.kohesive.injekt.injectLazy @@ -20,7 +20,7 @@ data class ALManga( val total_chapters: Int, ) { - fun toTrack() = TrackSearch.create(TrackManager.ANILIST).apply { + fun toTrack() = TrackSearch.create(TrackerManager.ANILIST).apply { media_id = this@ALManga.media_id title = title_user_pref total_chapters = this@ALManga.total_chapters @@ -50,7 +50,7 @@ data class ALUserManga( val manga: ALManga, ) { - fun toTrack() = Track.create(TrackManager.ANILIST).apply { + fun toTrack() = Track.create(TrackerManager.ANILIST).apply { media_id = manga.media_id title = manga.title_user_pref status = toTrackStatus() @@ -62,7 +62,7 @@ data class ALUserManga( total_chapters = manga.total_chapters } - fun toTrackStatus() = when (list_status) { + private fun toTrackStatus() = when (list_status) { "CURRENT" -> Anilist.READING "COMPLETED" -> Anilist.COMPLETED "PAUSED" -> Anilist.ON_HOLD diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt index f5d8ecc0d..71aff2f2a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt @@ -4,19 +4,19 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy -class Bangumi(id: Long) : TrackService(id, "Bangumi") { +class Bangumi(id: Long) : Tracker(id, "Bangumi") { private val json: Json by injectLazy() private val interceptor by lazy { BangumiInterceptor(this) } - private val api by lazy { BangumiApi(client, interceptor) } + private val api by lazy { BangumiApi(id, client, interceptor) } override fun getScoreList(): List { return IntRange(0, 10).map(Int::toString) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt index 444487df1..6762fdcaf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt @@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.track.bangumi import android.net.Uri import androidx.core.net.toUri import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST @@ -26,7 +25,11 @@ import uy.kohesive.injekt.injectLazy import java.net.URLEncoder import java.nio.charset.StandardCharsets -class BangumiApi(private val client: OkHttpClient, interceptor: BangumiInterceptor) { +class BangumiApi( + private val trackId: Long, + private val client: OkHttpClient, + interceptor: BangumiInterceptor, +) { private val json: Json by injectLazy() @@ -105,7 +108,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept } else { 0 } - return TrackSearch.create(TrackManager.BANGUMI).apply { + return TrackSearch.create(trackId).apply { media_id = obj["id"]!!.jsonPrimitive.long title = obj["name_cn"]!!.jsonPrimitive.content cover_url = coverUrl diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt index c11730754..f90038161 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt @@ -1,20 +1,21 @@ package eu.kanade.tachiyomi.data.track.kavita -import android.content.Context -import android.content.SharedPreferences import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.EnhancedTrackService -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.EnhancedTracker +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch +import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.Source import tachiyomi.domain.manga.model.Manga +import tachiyomi.domain.source.service.SourceManager +import uy.kohesive.injekt.injectLazy import java.security.MessageDigest import tachiyomi.domain.track.model.Track as DomainTrack -class Kavita(private val context: Context, id: Long) : TrackService(id, "Kavita"), EnhancedTrackService { +class Kavita(id: Long) : Tracker(id, "Kavita"), EnhancedTracker { companion object { const val UNREAD = 1 @@ -27,6 +28,8 @@ class Kavita(private val context: Context, id: Long) : TrackService(id, "Kavita" private val interceptor by lazy { KavitaInterceptor(this) } val api by lazy { KavitaApi(client, interceptor) } + private val sourceManager: SourceManager by injectLazy() + override fun getLogo(): Int = R.drawable.ic_tracker_kavita override fun getLogoColor() = Color.rgb(74, 198, 148) @@ -83,7 +86,7 @@ class Kavita(private val context: Context, id: Long) : TrackService(id, "Kavita" saveCredentials("user", "pass") } - // TrackService.isLogged works by checking that credentials are saved. + // [Tracker].isLogged works by checking that credentials are saved. // By saving dummy, unused credentials, we can activate the tracker simply by login/logout override fun loginNoop() { saveCredentials("user", "pass") @@ -110,28 +113,29 @@ class Kavita(private val context: Context, id: Long) : TrackService(id, "Kavita" fun loadOAuth() { val oauth = OAuth() - for (sourceId in 1..3) { - val authentication = oauth.authentications[sourceId - 1] - val sourceSuffixID by lazy { - val key = "kavita_$sourceId/all/1" // Hardcoded versionID to 1 + for (id in 1..3) { + val authentication = oauth.authentications[id - 1] + val sourceId by lazy { + val key = "kavita_$id/all/1" // Hardcoded versionID to 1 val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray()) (0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) } .reduce(Long::or) and Long.MAX_VALUE } - val preferences: SharedPreferences by lazy { - context.getSharedPreferences("source_$sourceSuffixID", Context.MODE_PRIVATE) - } - val prefApiUrl = preferences.getString("APIURL", "")!! - if (prefApiUrl.isEmpty()) { + val preferences = (sourceManager.get(sourceId) as ConfigurableSource).getPreferences() + + val prefApiUrl = preferences.getString("APIURL", "") + val prefApiKey = preferences.getString("APIKEY", "") + if (prefApiUrl.isNullOrEmpty() || prefApiKey.isNullOrEmpty()) { // Source not configured. Skip continue } - val prefApiKey = preferences.getString("APIKEY", "")!! + val token = api.getNewToken(apiUrl = prefApiUrl, apiKey = prefApiKey) if (token.isNullOrEmpty()) { // Source is not accessible. Skip continue } + authentication.apiUrl = prefApiUrl authentication.jwtToken = token.toString() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaModels.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaModels.kt index 3900c3f39..6f42f6836 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaModels.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaModels.kt @@ -1,6 +1,6 @@ package eu.kanade.tachiyomi.data.track.kavita -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.Serializable @@ -22,7 +22,7 @@ data class SeriesDto( val libraryId: Int, val libraryName: String? = "", ) { - fun toTrack(): TrackSearch = TrackSearch.create(TrackManager.KAVITA).also { + fun toTrack(): TrackSearch = TrackSearch.create(TrackerManager.KAVITA).also { it.title = name it.summary = "" } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt index ade2456bb..a2764c685 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt @@ -4,15 +4,15 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.DeletableTrackService -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.DeletableTracker +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy import java.text.DecimalFormat -class Kitsu(id: Long) : TrackService(id, "Kitsu"), DeletableTrackService { +class Kitsu(id: Long) : Tracker(id, "Kitsu"), DeletableTracker { companion object { const val READING = 1 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt index 915c7ae8b..1cbf16c71 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.data.track.kitsu import androidx.annotation.CallSuper import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonObject @@ -35,7 +35,7 @@ class KitsuSearchManga(obj: JsonObject) { private val endDate = obj["endDate"]?.jsonPrimitive?.contentOrNull @CallSuper - fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply { + fun toTrack() = TrackSearch.create(TrackerManager.KITSU).apply { media_id = this@KitsuSearchManga.id title = canonicalTitle total_chapters = chapterCount ?: 0 @@ -67,7 +67,7 @@ class KitsuLibManga(obj: JsonObject, manga: JsonObject) { private val ratingTwenty = obj["attributes"]!!.jsonObject["ratingTwenty"]?.jsonPrimitive?.contentOrNull val progress = obj["attributes"]!!.jsonObject["progress"]!!.jsonPrimitive.int - fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply { + fun toTrack() = TrackSearch.create(TrackerManager.KITSU).apply { media_id = libraryId title = canonicalTitle total_chapters = chapterCount ?: 0 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt index 8937bd21a..450e502be 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt @@ -4,8 +4,8 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.EnhancedTrackService -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.EnhancedTracker +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.source.Source import okhttp3.Dns @@ -13,7 +13,7 @@ import okhttp3.OkHttpClient import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.track.model.Track as DomainTrack -class Komga(id: Long) : TrackService(id, "Komga"), EnhancedTrackService { +class Komga(id: Long) : Tracker(id, "Komga"), EnhancedTracker { companion object { const val UNREAD = 1 @@ -26,7 +26,7 @@ class Komga(id: Long) : TrackService(id, "Komga"), EnhancedTrackService { .dns(Dns.SYSTEM) // don't use DNS over HTTPS as it breaks IP addressing .build() - val api by lazy { KomgaApi(client) } + val api by lazy { KomgaApi(id, client) } override fun getLogo() = R.drawable.ic_tracker_komga @@ -85,7 +85,7 @@ class Komga(id: Long) : TrackService(id, "Komga"), EnhancedTrackService { saveCredentials("user", "pass") } - // TrackService.isLogged works by checking that credentials are saved. + // [Tracker].isLogged works by checking that credentials are saved. // By saving dummy, unused credentials, we can activate the tracker simply by login/logout override fun loginNoop() { saveCredentials("user", "pass") diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt index 89e7fafbd..5992727ae 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.data.track.komga import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.awaitSuccess @@ -19,7 +18,10 @@ import uy.kohesive.injekt.injectLazy private const val READLIST_API = "/api/v1/readlists" -class KomgaApi(private val client: OkHttpClient) { +class KomgaApi( + private val trackId: Long, + private val client: OkHttpClient, +) { private val json: Json by injectLazy() @@ -85,13 +87,13 @@ class KomgaApi(private val client: OkHttpClient) { return getTrackSearch(track.tracking_url) } - private fun SeriesDto.toTrack(): TrackSearch = TrackSearch.create(TrackManager.KOMGA).also { + private fun SeriesDto.toTrack(): TrackSearch = TrackSearch.create(trackId).also { it.title = metadata.title it.summary = metadata.summary it.publishing_status = metadata.status } - private fun ReadListDto.toTrack(): TrackSearch = TrackSearch.create(TrackManager.KOMGA).also { + private fun ReadListDto.toTrack(): TrackSearch = TrackSearch.create(trackId).also { it.title = name } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt index 33df93222..417f6acb8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt @@ -4,13 +4,13 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.DeletableTrackService -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.DeletableTracker +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch -class MangaUpdates(id: Long) : TrackService(id, "MangaUpdates"), DeletableTrackService { +class MangaUpdates(id: Long) : Tracker(id, "MangaUpdates"), DeletableTracker { companion object { const val READING_LIST = 0 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt index 3acbb035d..cd0d1eb1b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt @@ -4,14 +4,14 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.DeletableTrackService -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.DeletableTracker +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy -class MyAnimeList(id: Long) : TrackService(id, "MyAnimeList"), DeletableTrackService { +class MyAnimeList(id: Long) : Tracker(id, "MyAnimeList"), DeletableTracker { companion object { const val READING = 1 @@ -28,7 +28,7 @@ class MyAnimeList(id: Long) : TrackService(id, "MyAnimeList"), DeletableTrackSer private val json: Json by injectLazy() private val interceptor by lazy { MyAnimeListInterceptor(this, getPassword()) } - private val api by lazy { MyAnimeListApi(client, interceptor) } + private val api by lazy { MyAnimeListApi(id, client, interceptor) } override val supportsReadingDates: Boolean = true diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt index 1bfb4e581..d66a4c561 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt @@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.track.myanimelist import android.net.Uri import androidx.core.net.toUri import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST @@ -32,7 +31,11 @@ import uy.kohesive.injekt.injectLazy import java.text.SimpleDateFormat import java.util.Locale -class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListInterceptor) { +class MyAnimeListApi( + private val trackId: Long, + private val client: OkHttpClient, + interceptor: MyAnimeListInterceptor, +) { private val json: Json by injectLazy() @@ -106,7 +109,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI .parseAs() .let { val obj = it.jsonObject - TrackSearch.create(TrackManager.MYANIMELIST).apply { + TrackSearch.create(trackId).apply { media_id = obj["id"]!!.jsonPrimitive.long title = obj["title"]!!.jsonPrimitive.content summary = obj["synopsis"]?.jsonPrimitive?.content ?: "" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt index 463059055..312c9acbd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt @@ -4,14 +4,14 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.DeletableTrackService -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.DeletableTracker +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy -class Shikimori(id: Long) : TrackService(id, "Shikimori"), DeletableTrackService { +class Shikimori(id: Long) : Tracker(id, "Shikimori"), DeletableTracker { companion object { const val READING = 1 @@ -26,7 +26,7 @@ class Shikimori(id: Long) : TrackService(id, "Shikimori"), DeletableTrackService private val interceptor by lazy { ShikimoriInterceptor(this) } - private val api by lazy { ShikimoriApi(client, interceptor) } + private val api by lazy { ShikimoriApi(id, client, interceptor) } override fun getScoreList(): List { return IntRange(0, 10).map(Int::toString) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt index 0137ed6df..fd62f18fc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt @@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.data.track.shikimori import androidx.core.net.toUri import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.DELETE import eu.kanade.tachiyomi.network.GET @@ -28,7 +27,11 @@ import okhttp3.RequestBody.Companion.toRequestBody import tachiyomi.core.util.lang.withIOContext import uy.kohesive.injekt.injectLazy -class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInterceptor) { +class ShikimoriApi( + private val trackId: Long, + private val client: OkHttpClient, + interceptor: ShikimoriInterceptor, +) { private val json: Json by injectLazy() @@ -96,7 +99,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter } private fun jsonToSearch(obj: JsonObject): TrackSearch { - return TrackSearch.create(TrackManager.SHIKIMORI).apply { + return TrackSearch.create(trackId).apply { media_id = obj["id"]!!.jsonPrimitive.long title = obj["name"]!!.jsonPrimitive.content total_chapters = obj["chapters"]!!.jsonPrimitive.int @@ -110,7 +113,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter } private fun jsonToTrack(obj: JsonObject, mangas: JsonObject): Track { - return Track.create(TrackManager.SHIKIMORI).apply { + return Track.create(trackId).apply { title = mangas["name"]!!.jsonPrimitive.content media_id = obj["id"]!!.jsonPrimitive.long total_chapters = mangas["chapters"]!!.jsonPrimitive.int diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt index 3958bfa2e..2c7fd67c4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt @@ -4,16 +4,16 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.EnhancedTrackService -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.EnhancedTracker +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.source.Source import tachiyomi.domain.manga.model.Manga as DomainManga import tachiyomi.domain.track.model.Track as DomainTrack -class Suwayomi(id: Long) : TrackService(id, "Suwayomi"), EnhancedTrackService { +class Suwayomi(id: Long) : Tracker(id, "Suwayomi"), EnhancedTracker { - val api by lazy { TachideskApi() } + val api by lazy { SuwayomiApi(id) } override fun getLogo() = R.drawable.ic_tracker_suwayomi diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiApi.kt similarity index 87% rename from app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiApi.kt index 86227095d..5c5367bec 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiApi.kt @@ -4,7 +4,6 @@ import android.app.Application import android.content.Context import android.content.SharedPreferences import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.NetworkHelper @@ -24,7 +23,7 @@ import uy.kohesive.injekt.injectLazy import java.nio.charset.Charset import java.security.MessageDigest -class TachideskApi { +class SuwayomiApi(private val trackId: Long) { private val network: NetworkHelper by injectLazy() private val json: Json by injectLazy() @@ -62,7 +61,7 @@ class TachideskApi { .parseAs() } - TrackSearch.create(TrackManager.SUWAYOMI).apply { + TrackSearch.create(trackId).apply { title = manga.title cover_url = "$url/thumbnail" summary = manga.description.orEmpty() @@ -101,26 +100,24 @@ class TachideskApi { return getTrackSearch(track.tracking_url) } - private val tachideskExtensionId by lazy { + private val sourceId by lazy { val key = "tachidesk/en/1" val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray()) (0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE } private val preferences: SharedPreferences by lazy { - Injekt.get().getSharedPreferences("source_$tachideskExtensionId", Context.MODE_PRIVATE) + Injekt.get().getSharedPreferences("source_$sourceId", Context.MODE_PRIVATE) } private fun getPrefBaseUrl(): String = preferences.getString(ADDRESS_TITLE, ADDRESS_DEFAULT)!! private fun getPrefBaseLogin(): String = preferences.getString(LOGIN_TITLE, LOGIN_DEFAULT)!! private fun getPrefBasePassword(): String = preferences.getString(PASSWORD_TITLE, PASSWORD_DEFAULT)!! - - companion object { - private const val ADDRESS_TITLE = "Server URL Address" - private const val ADDRESS_DEFAULT = "" - private const val LOGIN_TITLE = "Login (Basic Auth)" - private const val LOGIN_DEFAULT = "" - private const val PASSWORD_TITLE = "Password (Basic Auth)" - private const val PASSWORD_DEFAULT = "" - } } + +private const val ADDRESS_TITLE = "Server URL Address" +private const val ADDRESS_DEFAULT = "" +private const val LOGIN_TITLE = "Login (Basic Auth)" +private const val LOGIN_DEFAULT = "" +private const val PASSWORD_TITLE = "Password (Basic Auth)" +private const val PASSWORD_DEFAULT = "" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskDto.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiModels.kt similarity index 100% rename from app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskDto.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiModels.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt index ab1431fe8..ac8964412 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt @@ -35,8 +35,8 @@ import eu.kanade.domain.manga.model.toSManga import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.download.DownloadManager -import eu.kanade.tachiyomi.data.track.EnhancedTrackService -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.EnhancedTracker +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags @@ -177,7 +177,7 @@ internal class MigrateDialogScreenModel( } private val enhancedServices by lazy { - Injekt.get().services.filterIsInstance() + Injekt.get().trackers.filterIsInstance() } suspend fun migrateManga( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt index 188b148eb..b99a67608 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt @@ -15,16 +15,12 @@ import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.coroutineScope import eu.kanade.core.preference.asState import eu.kanade.domain.base.BasePreferences -import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.source.service.SourcePreferences -import eu.kanade.domain.track.model.toDomainTrack +import eu.kanade.domain.track.interactor.AddTracks import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.tachiyomi.data.cache.CoverCache -import eu.kanade.tachiyomi.data.track.EnhancedTrackService -import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.util.removeCovers @@ -37,11 +33,9 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import logcat.LogPriority import tachiyomi.core.preference.CheckboxState import tachiyomi.core.preference.mapAsCheckboxState import tachiyomi.core.util.lang.launchIO -import tachiyomi.core.util.system.logcat import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.interactor.SetMangaCategories import tachiyomi.domain.category.model.Category @@ -54,7 +48,6 @@ import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.toMangaUpdate import tachiyomi.domain.source.interactor.GetRemoteManga import tachiyomi.domain.source.service.SourceManager -import tachiyomi.domain.track.interactor.InsertTrack import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.util.Date @@ -76,12 +69,9 @@ class BrowseSourceScreenModel( private val getManga: GetManga = Injekt.get(), private val networkToLocalManga: NetworkToLocalManga = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), - private val insertTrack: InsertTrack = Injekt.get(), - private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack = Injekt.get(), + private val addTracks: AddTracks = Injekt.get(), ) : StateScreenModel(State(Listing.valueOf(listingQuery))) { - private val loggedServices by lazy { Injekt.get().services.filter { it.isLoggedIn } } - var displayMode by sourcePreferences.sourceDisplayMode().asState(coroutineScope) val source = sourceManager.getOrStub(sourceId) @@ -243,8 +233,7 @@ class BrowseSourceScreenModel( new = new.removeCovers(coverCache) } else { setMangaDefaultChapterFlags.await(manga) - - autoAddTrack(manga) + addTracks.bindEnhancedTracks(manga, source) } updateManga.await(new.toMangaUpdate()) @@ -281,25 +270,6 @@ class BrowseSourceScreenModel( } } - private suspend fun autoAddTrack(manga: Manga) { - loggedServices - .filterIsInstance() - .filter { it.accept(source) } - .forEach { service -> - try { - service.match(manga)?.let { track -> - track.manga_id = manga.id - (service as TrackService).bind(track) - insertTrack.await(track.toDomainTrack()!!) - - syncChapterProgressWithTrack.await(manga.id, track.toDomainTrack()!!, service) - } - } catch (e: Exception) { - logcat(LogPriority.WARN, e) { "Could not match manga: ${manga.title} with service $service" } - } - } - } - /** * Get user categories. * diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt index 99b964cae..3f0408094 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt @@ -23,7 +23,7 @@ import eu.kanade.presentation.manga.DownloadAction import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.download.DownloadCache import eu.kanade.tachiyomi.data.download.DownloadManager -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.util.chapter.getNextUnread @@ -88,7 +88,7 @@ class LibraryScreenModel( private val sourceManager: SourceManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(), private val downloadCache: DownloadCache = Injekt.get(), - private val trackManager: TrackManager = Injekt.get(), + private val trackerManager: TrackerManager = Injekt.get(), ) : StateScreenModel(State()) { var activeCategoryIndex: Int by libraryPreferences.lastUsedCategory().asState(coroutineScope) @@ -101,9 +101,9 @@ class LibraryScreenModel( getTracksPerManga.subscribe(), getTrackingFilterFlow(), downloadCache.changes, - ) { searchQuery, library, tracks, loggedInTrackServices, _ -> + ) { searchQuery, library, tracks, loggedInTrackers, _ -> library - .applyFilters(tracks, loggedInTrackServices) + .applyFilters(tracks, loggedInTrackers) .applySort() .mapValues { (_, value) -> if (searchQuery != null) { @@ -169,7 +169,7 @@ class LibraryScreenModel( */ private suspend fun LibraryMap.applyFilters( trackMap: Map>, - loggedInTrackServices: Map, + loggedInTrackers: Map, ): LibraryMap { val prefs = getLibraryItemPreferencesFlow().first() val downloadedOnly = prefs.globalFilterDownloaded @@ -180,10 +180,10 @@ class LibraryScreenModel( val filterBookmarked = prefs.filterBookmarked val filterCompleted = prefs.filterCompleted - val isNotLoggedInAnyTrack = loggedInTrackServices.isEmpty() + val isNotLoggedInAnyTrack = loggedInTrackers.isEmpty() - val excludedTracks = loggedInTrackServices.mapNotNull { if (it.value == TriState.ENABLED_NOT) it.key else null } - val includedTracks = loggedInTrackServices.mapNotNull { if (it.value == TriState.ENABLED_IS) it.key else null } + val excludedTracks = loggedInTrackers.mapNotNull { if (it.value == TriState.ENABLED_NOT) it.key else null } + val includedTracks = loggedInTrackers.mapNotNull { if (it.value == TriState.ENABLED_IS) it.key else null } val trackFiltersIsIgnored = includedTracks.isEmpty() && excludedTracks.isEmpty() val filterFnDownloaded: (LibraryItem) -> Boolean = { @@ -366,14 +366,14 @@ class LibraryScreenModel( * @return map of track id with the filter value */ private fun getTrackingFilterFlow(): Flow> { - val loggedServices = trackManager.services.filter { it.isLoggedIn } - return if (loggedServices.isNotEmpty()) { - val prefFlows = loggedServices + val loggedInTrackers = trackerManager.trackers.filter { it.isLoggedIn } + return if (loggedInTrackers.isNotEmpty()) { + val prefFlows = loggedInTrackers .map { libraryPreferences.filterTracking(it.id.toInt()).changes() } .toTypedArray() combine(*prefFlows) { - loggedServices - .mapIndexed { index, trackService -> trackService.id to it[index] } + loggedInTrackers + .mapIndexed { index, tracker -> tracker.id to it[index] } .toMap() } } else { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt index 1a9ce4208..2a59af85c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt @@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.ui.library import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.coroutineScope import eu.kanade.domain.base.BasePreferences -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import tachiyomi.core.preference.Preference import tachiyomi.core.preference.TriState import tachiyomi.core.preference.getAndSet @@ -22,11 +22,11 @@ class LibrarySettingsScreenModel( val libraryPreferences: LibraryPreferences = Injekt.get(), private val setDisplayMode: SetDisplayMode = Injekt.get(), private val setSortModeForCategory: SetSortModeForCategory = Injekt.get(), - private val trackManager: TrackManager = Injekt.get(), + private val trackerManager: TrackerManager = Injekt.get(), ) : ScreenModel { - val trackServices - get() = trackManager.services.filter { it.isLoggedIn } + val trackers + get() = trackerManager.trackers.filter { it.isLoggedIn } fun toggleFilter(preference: (LibraryPreferences) -> Preference) { preference(libraryPreferences).getAndSet { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 868a8cee7..1d67ab668 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -138,7 +138,7 @@ class MainActivity : BaseActivity() { libraryPreferences = libraryPreferences, readerPreferences = Injekt.get(), backupPreferences = Injekt.get(), - trackManager = Injekt.get(), + trackerManager = Injekt.get(), ) } else { false diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index 0827caded..9e94a2605 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -23,9 +23,9 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.download.DownloadCache import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.model.Download -import eu.kanade.tachiyomi.data.track.EnhancedTrackService -import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.EnhancedTracker +import eu.kanade.tachiyomi.data.track.Tracker +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.network.HttpException import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.ui.manga.track.TrackItem @@ -84,7 +84,7 @@ class MangaScreenModel( private val libraryPreferences: LibraryPreferences = Injekt.get(), readerPreferences: ReaderPreferences = Injekt.get(), uiPreferences: UiPreferences = Injekt.get(), - private val trackManager: TrackManager = Injekt.get(), + private val trackerManager: TrackerManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(), private val downloadCache: DownloadCache = Injekt.get(), private val getMangaAndChapters: GetMangaWithChapters = Injekt.get(), @@ -105,7 +105,7 @@ class MangaScreenModel( private val successState: State.Success? get() = state.value as? State.Success - private val loggedServices by lazy { trackManager.services.filter { it.isLoggedIn } } + private val loggedInTrackers by lazy { trackerManager.trackers.filter { it.isLoggedIn } } val manga: Manga? get() = successState?.manga @@ -317,14 +317,14 @@ class MangaScreenModel( // Finally match with enhanced tracking when available val source = state.source state.trackItems - .map { it.service } - .filterIsInstance() + .map { it.tracker } + .filterIsInstance() .filter { it.accept(source) } .forEach { service -> launchIO { try { service.match(manga)?.let { track -> - (service as TrackService).register(track, mangaId) + (service as Tracker).register(track, mangaId) } } catch (e: Exception) { logcat(LogPriority.WARN, e) { @@ -949,11 +949,11 @@ class MangaScreenModel( getTracks.subscribe(manga.id) .catch { logcat(LogPriority.ERROR, it) } .map { tracks -> - loggedServices + loggedInTrackers // Map to TrackItem .map { service -> TrackItem(tracks.find { it.syncId == service.id }, service) } // Show only if the service supports this manga's source - .filter { (it.service as? EnhancedTrackService)?.accept(source!!) ?: true } + .filter { (it.tracker as? EnhancedTracker)?.accept(source!!) ?: true } } .distinctUntilChanged() .collectLatest { trackItems -> diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index f92374b2a..f25dab5c8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -46,14 +46,14 @@ import eu.kanade.presentation.track.TrackChapterSelector import eu.kanade.presentation.track.TrackDateSelector import eu.kanade.presentation.track.TrackInfoDialogHome import eu.kanade.presentation.track.TrackScoreSelector -import eu.kanade.presentation.track.TrackServiceSearch import eu.kanade.presentation.track.TrackStatusSelector +import eu.kanade.presentation.track.TrackerSearch import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.track.DeletableTrackService -import eu.kanade.tachiyomi.data.track.EnhancedTrackService -import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.DeletableTracker +import eu.kanade.tachiyomi.data.track.EnhancedTracker +import eu.kanade.tachiyomi.data.track.Tracker +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone import eu.kanade.tachiyomi.util.system.openInBrowser @@ -105,7 +105,7 @@ data class TrackInfoDialogHomeScreen( navigator.push( TrackStatusSelectorScreen( track = it.track!!, - serviceId = it.service.id, + serviceId = it.tracker.id, ), ) }, @@ -113,7 +113,7 @@ data class TrackInfoDialogHomeScreen( navigator.push( TrackChapterSelectorScreen( track = it.track!!, - serviceId = it.service.id, + serviceId = it.tracker.id, ), ) }, @@ -121,7 +121,7 @@ data class TrackInfoDialogHomeScreen( navigator.push( TrackScoreSelectorScreen( track = it.track!!, - serviceId = it.service.id, + serviceId = it.tracker.id, ), ) }, @@ -129,7 +129,7 @@ data class TrackInfoDialogHomeScreen( navigator.push( TrackDateSelectorScreen( track = it.track!!, - serviceId = it.service.id, + serviceId = it.tracker.id, start = true, ), ) @@ -138,21 +138,21 @@ data class TrackInfoDialogHomeScreen( navigator.push( TrackDateSelectorScreen( track = it.track!!, - serviceId = it.service.id, + serviceId = it.tracker.id, start = false, ), ) }, onNewSearch = { - if (it.service is EnhancedTrackService) { + if (it.tracker is EnhancedTracker) { sm.registerEnhancedTracking(it) } else { navigator.push( - TrackServiceSearchScreen( + TrackerSearchScreen( mangaId = mangaId, initialQuery = it.track?.title ?: mangaTitle, currentUrl = it.track?.remoteUrl, - serviceId = it.service.id, + serviceId = it.tracker.id, ), ) } @@ -160,10 +160,10 @@ data class TrackInfoDialogHomeScreen( onOpenInBrowser = { openTrackerInBrowser(context, it) }, onRemoved = { navigator.push( - TrackServiceRemoveScreen( + TrackerRemoveScreen( mangaId = mangaId, track = it.track!!, - serviceId = it.service.id, + serviceId = it.tracker.id, ), ) }, @@ -201,12 +201,12 @@ data class TrackInfoDialogHomeScreen( } fun registerEnhancedTracking(item: TrackItem) { - item.service as EnhancedTrackService + item.tracker as EnhancedTracker coroutineScope.launchNonCancellable { val manga = Injekt.get().await(mangaId) ?: return@launchNonCancellable try { - val matchResult = item.service.match(manga) ?: throw Exception() - item.service.register(matchResult, mangaId) + val matchResult = item.tracker.match(manga) ?: throw Exception() + item.tracker.register(matchResult, mangaId) } catch (e: Exception) { withUIContext { Injekt.get().toast(R.string.error_no_match) } } @@ -236,13 +236,13 @@ data class TrackInfoDialogHomeScreen( } private fun List.mapToTrackItem(): List { - val loggedServices = Injekt.get().services.filter { it.isLoggedIn } + val loggedInTrackers = Injekt.get().trackers.filter { it.isLoggedIn } val source = Injekt.get().getOrStub(sourceId) - return loggedServices + return loggedInTrackers // Map to TrackItem .map { service -> TrackItem(find { it.syncId == service.id }, service) } // Show only if the service supports this manga's source - .filter { (it.service as? EnhancedTrackService)?.accept(source) ?: true } + .filter { (it.tracker as? EnhancedTracker)?.accept(source) ?: true } } @Immutable @@ -263,7 +263,7 @@ private data class TrackStatusSelectorScreen( val sm = rememberScreenModel { Model( track = track, - service = Injekt.get().getService(serviceId)!!, + tracker = Injekt.get().get(serviceId)!!, ) } val state by sm.state.collectAsState() @@ -281,11 +281,11 @@ private data class TrackStatusSelectorScreen( private class Model( private val track: Track, - private val service: TrackService, + private val tracker: Tracker, ) : StateScreenModel(State(track.status.toInt())) { fun getSelections(): Map { - return service.getStatusList().associateWith { service.getStatus(it) } + return tracker.getStatusList().associateWith { tracker.getStatus(it) } } fun setSelection(selection: Int) { @@ -294,7 +294,7 @@ private data class TrackStatusSelectorScreen( fun setStatus() { coroutineScope.launchNonCancellable { - service.setRemoteStatus(track.toDbTrack(), state.value.selection) + tracker.setRemoteStatus(track.toDbTrack(), state.value.selection) } } @@ -316,7 +316,7 @@ private data class TrackChapterSelectorScreen( val sm = rememberScreenModel { Model( track = track, - service = Injekt.get().getService(serviceId)!!, + tracker = Injekt.get().get(serviceId)!!, ) } val state by sm.state.collectAsState() @@ -335,7 +335,7 @@ private data class TrackChapterSelectorScreen( private class Model( private val track: Track, - private val service: TrackService, + private val tracker: Tracker, ) : StateScreenModel(State(track.lastChapterRead.toInt())) { fun getRange(): Iterable { @@ -353,7 +353,7 @@ private data class TrackChapterSelectorScreen( fun setChapter() { coroutineScope.launchNonCancellable { - service.setRemoteLastChapterRead(track.toDbTrack(), state.value.selection) + tracker.setRemoteLastChapterRead(track.toDbTrack(), state.value.selection) } } @@ -375,7 +375,7 @@ private data class TrackScoreSelectorScreen( val sm = rememberScreenModel { Model( track = track, - service = Injekt.get().getService(serviceId)!!, + tracker = Injekt.get().get(serviceId)!!, ) } val state by sm.state.collectAsState() @@ -394,11 +394,11 @@ private data class TrackScoreSelectorScreen( private class Model( private val track: Track, - private val service: TrackService, - ) : StateScreenModel(State(service.displayScore(track.toDbTrack()))) { + private val tracker: Tracker, + ) : StateScreenModel(State(tracker.displayScore(track.toDbTrack()))) { fun getSelections(): List { - return service.getScoreList() + return tracker.getScoreList() } fun setSelection(selection: String) { @@ -407,7 +407,7 @@ private data class TrackScoreSelectorScreen( fun setScore() { coroutineScope.launchNonCancellable { - service.setRemoteScore(track.toDbTrack(), state.value.selection) + tracker.setRemoteScore(track.toDbTrack(), state.value.selection) } } @@ -486,7 +486,7 @@ private data class TrackDateSelectorScreen( val sm = rememberScreenModel { Model( track = track, - service = Injekt.get().getService(serviceId)!!, + tracker = Injekt.get().get(serviceId)!!, start = start, ) } @@ -515,7 +515,7 @@ private data class TrackDateSelectorScreen( private class Model( private val track: Track, - private val service: TrackService, + private val tracker: Tracker, private val start: Boolean, ) : ScreenModel { @@ -534,15 +534,15 @@ private data class TrackDateSelectorScreen( val localMillis = millis.convertEpochMillisZone(ZoneOffset.UTC, ZoneOffset.systemDefault()) coroutineScope.launchNonCancellable { if (start) { - service.setRemoteStartDate(track.toDbTrack(), localMillis) + tracker.setRemoteStartDate(track.toDbTrack(), localMillis) } else { - service.setRemoteFinishDate(track.toDbTrack(), localMillis) + tracker.setRemoteFinishDate(track.toDbTrack(), localMillis) } } } fun confirmRemoveDate(navigator: Navigator) { - navigator.push(TrackDateRemoverScreen(track, service.id, start)) + navigator.push(TrackDateRemoverScreen(track, tracker.id, start)) } } } @@ -559,7 +559,7 @@ private data class TrackDateRemoverScreen( val sm = rememberScreenModel { Model( track = track, - service = Injekt.get().getService(serviceId)!!, + tracker = Injekt.get().get(serviceId)!!, start = start, ) } @@ -614,25 +614,25 @@ private data class TrackDateRemoverScreen( private class Model( private val track: Track, - private val service: TrackService, + private val tracker: Tracker, private val start: Boolean, ) : ScreenModel { - fun getServiceName() = service.name + fun getServiceName() = tracker.name fun removeDate() { coroutineScope.launchNonCancellable { if (start) { - service.setRemoteStartDate(track.toDbTrack(), 0) + tracker.setRemoteStartDate(track.toDbTrack(), 0) } else { - service.setRemoteFinishDate(track.toDbTrack(), 0) + tracker.setRemoteFinishDate(track.toDbTrack(), 0) } } } } } -data class TrackServiceSearchScreen( +data class TrackerSearchScreen( private val mangaId: Long, private val initialQuery: String, private val currentUrl: String?, @@ -647,14 +647,14 @@ data class TrackServiceSearchScreen( mangaId = mangaId, currentUrl = currentUrl, initialQuery = initialQuery, - service = Injekt.get().getService(serviceId)!!, + tracker = Injekt.get().get(serviceId)!!, ) } val state by sm.state.collectAsState() var textFieldValue by remember { mutableStateOf(TextFieldValue(initialQuery)) } - TrackServiceSearch( + TrackerSearch( query = textFieldValue, onQueryChange = { textFieldValue = it }, onDispatchQuery = { sm.trackingSearch(textFieldValue.text) }, @@ -673,7 +673,7 @@ data class TrackServiceSearchScreen( private val mangaId: Long, private val currentUrl: String? = null, initialQuery: String, - private val service: TrackService, + private val tracker: Tracker, ) : StateScreenModel(State()) { init { @@ -690,7 +690,7 @@ data class TrackServiceSearchScreen( val result = withIOContext { try { - val results = service.search(query) + val results = tracker.search(query) Result.success(results) } catch (e: Throwable) { Result.failure(e) @@ -706,7 +706,7 @@ data class TrackServiceSearchScreen( } fun registerTracking(item: TrackSearch) { - coroutineScope.launchNonCancellable { service.register(item, mangaId) } + coroutineScope.launchNonCancellable { tracker.register(item, mangaId) } } fun updateSelection(selected: TrackSearch) { @@ -721,7 +721,7 @@ data class TrackServiceSearchScreen( } } -private data class TrackServiceRemoveScreen( +private data class TrackerRemoveScreen( private val mangaId: Long, private val track: Track, private val serviceId: Long, @@ -734,10 +734,10 @@ private data class TrackServiceRemoveScreen( Model( mangaId = mangaId, track = track, - service = Injekt.get().getService(serviceId)!!, + tracker = Injekt.get().get(serviceId)!!, ) } - val serviceName = sm.getServiceName() + val serviceName = sm.getName() var removeRemoteTrack by remember { mutableStateOf(false) } AlertDialogContent( modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars), @@ -758,7 +758,7 @@ private data class TrackServiceRemoveScreen( Text( text = stringResource(R.string.track_delete_text, serviceName), ) - if (sm.isServiceDeletable()) { + if (sm.isDeletable()) { Row(verticalAlignment = Alignment.CenterVertically) { Checkbox(checked = removeRemoteTrack, onCheckedChange = { removeRemoteTrack = it }) Text(text = stringResource(R.string.track_delete_remote_text, serviceName)) @@ -798,17 +798,17 @@ private data class TrackServiceRemoveScreen( private class Model( private val mangaId: Long, private val track: Track, - private val service: TrackService, + private val tracker: Tracker, private val deleteTrack: DeleteTrack = Injekt.get(), ) : ScreenModel { - fun getServiceName() = service.name + fun getName() = tracker.name - fun isServiceDeletable() = service is DeletableTrackService + fun isDeletable() = tracker is DeletableTracker fun deleteMangaFromService() { coroutineScope.launchNonCancellable { - (service as DeletableTrackService).delete(track.toDbTrack()) + (tracker as DeletableTracker).delete(track.toDbTrack()) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt index d0883e593..fd46e0eec 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt @@ -1,6 +1,6 @@ package eu.kanade.tachiyomi.ui.manga.track -import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.data.track.Tracker import tachiyomi.domain.track.model.Track -data class TrackItem(val track: Track?, val service: TrackService) +data class TrackItem(val track: Track?, val tracker: Tracker) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BaseOAuthLoginActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BaseOAuthLoginActivity.kt index a1a91a003..92302d718 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BaseOAuthLoginActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BaseOAuthLoginActivity.kt @@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.ui.setting.track import android.content.Intent import android.net.Uri import android.os.Bundle -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.ui.base.activity.BaseActivity import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.util.view.setComposeContent @@ -12,7 +12,7 @@ import uy.kohesive.injekt.injectLazy abstract class BaseOAuthLoginActivity : BaseActivity() { - internal val trackManager: TrackManager by injectLazy() + internal val trackerManager: TrackerManager by injectLazy() abstract fun handleResult(data: Uri?) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLoginActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLoginActivity.kt index af13de51b..47cd88416 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLoginActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLoginActivity.kt @@ -20,11 +20,11 @@ class TrackLoginActivity : BaseOAuthLoginActivity() { val matchResult = regex.find(data.fragment.toString()) if (matchResult?.groups?.get(1) != null) { lifecycleScope.launchIO { - trackManager.aniList.login(matchResult.groups[1]!!.value) + trackerManager.aniList.login(matchResult.groups[1]!!.value) returnToSettings() } } else { - trackManager.aniList.logout() + trackerManager.aniList.logout() returnToSettings() } } @@ -33,11 +33,11 @@ class TrackLoginActivity : BaseOAuthLoginActivity() { val code = data.getQueryParameter("code") if (code != null) { lifecycleScope.launchIO { - trackManager.bangumi.login(code) + trackerManager.bangumi.login(code) returnToSettings() } } else { - trackManager.bangumi.logout() + trackerManager.bangumi.logout() returnToSettings() } } @@ -46,11 +46,11 @@ class TrackLoginActivity : BaseOAuthLoginActivity() { val code = data.getQueryParameter("code") if (code != null) { lifecycleScope.launchIO { - trackManager.myAnimeList.login(code) + trackerManager.myAnimeList.login(code) returnToSettings() } } else { - trackManager.myAnimeList.logout() + trackerManager.myAnimeList.logout() returnToSettings() } } @@ -59,11 +59,11 @@ class TrackLoginActivity : BaseOAuthLoginActivity() { val code = data.getQueryParameter("code") if (code != null) { lifecycleScope.launchIO { - trackManager.shikimori.login(code) + trackerManager.shikimori.login(code) returnToSettings() } } else { - trackManager.shikimori.logout() + trackerManager.shikimori.logout() returnToSettings() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt index 873bd2723..6131308d0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt @@ -10,7 +10,7 @@ import eu.kanade.core.util.fastMapNotNull import eu.kanade.presentation.more.stats.StatsScreenState import eu.kanade.presentation.more.stats.data.StatsData import eu.kanade.tachiyomi.data.download.DownloadManager -import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.source.model.SManga import kotlinx.coroutines.flow.update import tachiyomi.core.util.lang.launchIO @@ -33,10 +33,10 @@ class StatsScreenModel( private val getTotalReadDuration: GetTotalReadDuration = Injekt.get(), private val getTracks: GetTracks = Injekt.get(), private val preferences: LibraryPreferences = Injekt.get(), - private val trackManager: TrackManager = Injekt.get(), + private val trackerManager: TrackerManager = Injekt.get(), ) : StateScreenModel(StatsScreenState.Loading) { - private val loggedServices by lazy { trackManager.services.fastFilter { it.isLoggedIn } } + private val loggedInTrackers by lazy { trackerManager.trackers.fastFilter { it.isLoggedIn } } init { coroutineScope.launchIO { @@ -72,7 +72,7 @@ class StatsScreenModel( val trackersStatData = StatsData.Trackers( trackedTitleCount = mangaTrackMap.count { it.value.isNotEmpty() }, meanScore = meanScore, - trackerCount = loggedServices.size, + trackerCount = loggedInTrackers.size, ) mutableState.update { @@ -115,10 +115,10 @@ class StatsScreenModel( } private suspend fun getMangaTrackMap(libraryManga: List): Map> { - val loggedServicesIds = loggedServices.map { it.id }.toHashSet() + val loggedInTrackerIds = loggedInTrackers.map { it.id }.toHashSet() return libraryManga.associate { manga -> val tracks = getTracks.await(manga.id) - .fastFilter { it.syncId in loggedServicesIds } + .fastFilter { it.syncId in loggedInTrackerIds } manga.id to tracks } @@ -144,7 +144,7 @@ class StatsScreenModel( } private fun get10PointScore(track: Track): Double { - val service = trackManager.getService(track.syncId)!! + val service = trackerManager.get(track.syncId)!! return service.get10PointScore(track) } } diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index bed8f0836..8821087b2 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -459,13 +459,13 @@ Tracking guide Update progress after reading - Services - One-way sync to update the chapter progress in tracking services. Set up tracking for individual entries from their tracking button. - Enhanced services + Trackers + One-way sync to update the chapter progress in external tracker services. Set up tracking for individual entries from their tracking button. + Enhanced trackers Available but source not installed: %s - Services that provide enhanced features for specific sources. Entries are automatically tracked when added to your library. + Provides enhanced features for specific sources. Entries are automatically tracked when added to your library. Track - Tracking login + Tracker login Hide entries already in library From ed506f84951677a5772e06720fc5cf1442a99b9b Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 27 Sep 2023 22:22:04 -0400 Subject: [PATCH 38/59] Update SSIV and image-decoder Includes updated libwebp for CVE-2023-5129 --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 091b67f61..887f7237a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -44,8 +44,8 @@ coil-core = { module = "io.coil-kt:coil" } coil-gif = { module = "io.coil-kt:coil-gif" } coil-compose = { module = "io.coil-kt:coil-compose" } -subsamplingscaleimageview = "com.github.tachiyomiorg:subsampling-scale-image-view:c8e2650" -image-decoder = "com.github.tachiyomiorg:image-decoder:16eda64574" +subsamplingscaleimageview = "com.github.tachiyomiorg:subsampling-scale-image-view:a51fd97" +image-decoder = "com.github.tachiyomiorg:image-decoder:1388669a6a" natural-comparator = "com.github.gpanther:java-nat-sort:natural-comparator-1.1" From 66a938779df1e1400125b987c23c29ac411dda6d Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 27 Sep 2023 22:54:03 -0400 Subject: [PATCH 39/59] Update SSIV and image-decoder, except with partially revert to non-broken HEIF/AVIF support --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 887f7237a..2b3431d1a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -44,8 +44,8 @@ coil-core = { module = "io.coil-kt:coil" } coil-gif = { module = "io.coil-kt:coil-gif" } coil-compose = { module = "io.coil-kt:coil-compose" } -subsamplingscaleimageview = "com.github.tachiyomiorg:subsampling-scale-image-view:a51fd97" -image-decoder = "com.github.tachiyomiorg:image-decoder:1388669a6a" +subsamplingscaleimageview = "com.github.tachiyomiorg:subsampling-scale-image-view:7e57335" +image-decoder = "com.github.tachiyomiorg:image-decoder:fbd6601290" natural-comparator = "com.github.gpanther:java-nat-sort:natural-comparator-1.1" From afb1ee2200053f3ea0603f7db2283043792fb974 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 30 Sep 2023 14:36:06 -0400 Subject: [PATCH 40/59] Rename new method in ConfigurableSource to get preferences Maybe fixes #9969 --- .../eu/kanade/tachiyomi/data/track/kavita/Kavita.kt | 3 ++- .../eu/kanade/tachiyomi/source/SourceExtensions.kt | 2 -- .../extension/details/SourcePreferencesScreen.kt | 9 +++------ .../eu/kanade/tachiyomi/source/ConfigurableSource.kt | 10 ++++++++-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt index f90038161..cb6e52e68 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt @@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.sourcePreferences import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.injectLazy @@ -121,7 +122,7 @@ class Kavita(id: Long) : Tracker(id, "Kavita"), EnhancedTracker { (0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) } .reduce(Long::or) and Long.MAX_VALUE } - val preferences = (sourceManager.get(sourceId) as ConfigurableSource).getPreferences() + val preferences = (sourceManager.get(sourceId) as ConfigurableSource).sourcePreferences() val prefApiUrl = preferences.getString("APIURL", "") val prefApiKey = preferences.getString("APIKEY", "") diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt index 8f4faaaa9..7be9c4d20 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt @@ -10,8 +10,6 @@ import uy.kohesive.injekt.api.get fun Source.icon(): Drawable? = Injekt.get().getAppIconForSource(this.id) -fun Source.getPreferenceKey(): String = "source_$id" - fun Source.toStubSource(): StubSource = StubSource(id = id, lang = lang, name = name) fun Source.getNameForMangaInfo(): String { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/SourcePreferencesScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/SourcePreferencesScreen.kt index 78aa37109..4e391cb3e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/SourcePreferencesScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/SourcePreferencesScreen.kt @@ -39,7 +39,7 @@ import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.SharedPreferencesDataStore import eu.kanade.tachiyomi.source.ConfigurableSource -import eu.kanade.tachiyomi.source.getPreferenceKey +import eu.kanade.tachiyomi.source.sourcePreferences import eu.kanade.tachiyomi.widget.TachiyomiTextInputEditText.Companion.setIncognito import tachiyomi.domain.source.service.SourceManager import tachiyomi.presentation.core.components.material.Scaffold @@ -134,12 +134,9 @@ class SourcePreferencesFragment : PreferenceFragmentCompat() { private fun populateScreen(): PreferenceScreen { val sourceId = requireArguments().getLong(SOURCE_ID) - val source = Injekt.get().get(sourceId)!! + val source = Injekt.get().get(sourceId)!! as ConfigurableSource - check(source is ConfigurableSource) - - val sharedPreferences = requireContext().getSharedPreferences(source.getPreferenceKey(), Context.MODE_PRIVATE) - val dataStore = SharedPreferencesDataStore(sharedPreferences) + val dataStore = SharedPreferencesDataStore(source.sourcePreferences()) preferenceManager.preferenceDataStore = dataStore val sourceScreen = preferenceManager.createPreferenceScreen(requireContext()) diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt index 4be411e3b..ea5eb848e 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt @@ -13,8 +13,14 @@ interface ConfigurableSource : Source { * * @since extensions-lib 1.5 */ - fun getPreferences(): SharedPreferences = - Injekt.get().getSharedPreferences("source_$id", Context.MODE_PRIVATE) + fun getSourcePreferences(): SharedPreferences = + Injekt.get().getSharedPreferences(preferenceKey(), Context.MODE_PRIVATE) fun setupPreferenceScreen(screen: PreferenceScreen) } + +private fun ConfigurableSource.preferenceKey(): String = "source_$id" + +// TODO: use getSourcePreferences once all extensions are on ext-lib 1.5 +fun ConfigurableSource.sourcePreferences(): SharedPreferences = + Injekt.get().getSharedPreferences(preferenceKey(), Context.MODE_PRIVATE) From 509bee056313c7ea4d127da72aa242ec221a25d4 Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Sun, 1 Oct 2023 21:07:14 +0700 Subject: [PATCH 41/59] Add project icon (#9972) --- .gitignore | 3 ++- .idea/icon.png | Bin 0 -> 14070 bytes 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .idea/icon.png diff --git a/.gitignore b/.gitignore index 4bef655b0..6abb1d29e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,8 @@ /local.properties /.idea/workspace.xml .DS_Store -.idea/ +.idea/* +!.idea/icon.png *iml *.iml diff --git a/.idea/icon.png b/.idea/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ead7c32417b2071c5145738579fd5568fdaccc4c GIT binary patch literal 14070 zcmYLwbyOS76D@=Q!Gjkm1c&185Zt}cV#VE|xRl^d+ER)Xch_PqP~6>J3lw*km+$x9 zIWOlx{@d)%&fJ-~b2nO3T>%G^91{r%2}em$RvYpC=f6J?8sfk9vLiYYl0d7Htkhed z#iI-iA0oNMKA9*QN?OE65wx8$pbDXff^J?z!ekO$36CE@G*F0<6e_+HzE(4EyX}My zsAnuEDJiCB{LYxvcy3I0+1OZ53l`XZKlf3?kMXOjhUb{7Mv8ByUm=KBd_~tq_h~h6 z6%zyT!C?ssf3s@*v~u?{JuBC~t0YbjJ)rr!PBth*-SmPd1;cF%sS5TfAvQ7@+4G)6 z!W!)kDvxZDBB|(k*GWj8eFbg1IoG~x89M=Gd`lzgl4#Ev~4~P1hYuK{b z5|@8ZfJ)`?1rsy#A=wD#krO5{sA_et5dF1z%F#isfI4e32_Y#rq_WN9^H*e)3X(UD zQVKr&b>6v)ROsUr%cN-E>)yY8)JbQH9iyyf6ZY?HxeWO1xp4QcdHLON*7x!sh7EGR@m3hT&yfp7FP8 zF;=@ObCZv#Sr3D@2}fyFox_&kso~k7;Mr0W`ZCt>Ku;+?(Io_6m$h_%`{_Lv$7(%^5v|kT+_zx|f_JUe{++EGRBlyGyV`ou>#R{w=OxH* zuZNtUsvcf9jTiwN=&IvEJ*wCpUu~=c_wPxUS&vikK-btlBpB%-tTJSve7yx8a=<^v zORc<2TgSl_$Px(0fy_u8pv5!)$JfbB%R@jMJFFs-z&wZiAU z2Aqw~x+8P}puz^b>1HErRqE}8<@16SAkSRY?1}aSHcrt}RV>(IHK^A!C!kyhN{X~B;VKHc%Aojgs-pIr?$7Lu4aA)3A`thX;Kc30iwkvt35vOcDnH1=*rI4O? zG=aVs3suO4N)?KPnawSZaHIIc#awf9XQj4aJKyRj89RBe9^`$fwq=*xMa?~Lzf=Gm!427S!deJ7H- z9KpfoBvqxKK511KzABKqr))&Y`9fin+cngy zZ=~(yX-|D>&TtvFNhPzjTkF1G@{1YDrm3<`g4&9;W6j27?PkZi1D`Z?F6Ts%d=CvB zji&A2Nb}O3k(KX#zU_R6X8^#0jlY10fT7Qihy-IbiWcl0$77619}1XQ1+{soncj|A zrKN{z2+vVIuMb7!`1if3LC?H0GNQ=18UkHkp|%#g=bV|I^bwT~s#b7+f^fqERTN64 zMC$UaloD|-1vLa-D&qf%A%{%-n?T59QR|`)wd=R+t>GvOb33ZKAgC8vR z)arUzeJp^$H)U#2C#=)mOcS)@RARTMsb1yXP+h%EoA=%y5C2%H&)S}yfDbON2kcS~|Efr#3RCJN)uX!< zxBRmvw2cSEtT1ZiCVWP5h_Ug&t5#qD5O0m@?~hnF1(p~;MTp4DLf&1ytBB?k_dw=1 z_A%y{f6`QM$9W1y z&C5>sjNh-@Vb2v`fj0Z7jGh>++F${r^&Mn+1?h zdSN+-^XKTok+$Ht6M+Q}@&f2gV^Kb_&uhy)HtJZHeQ1Z?zrv1<&j%HGFZRQyii4 z(g8mb`$<7W1`LzhL$$Y;R;}My3ViDhF4aC3TQOys4?nQ5eB@_}#M;-O4pM9kx{t>C z`KYb)?xFMN8O1I8BV*9gcg0KpLIpL7+ThJ^JK7m;ARd4|iw0uJyPSFQLf^=Sy$Eqs z^@+4{8MJs~wJQBIKWe*IX#vx9OixZ%_ASq={sGt5b6D;1{(oB6Gc6s@1;{HDsTI^N z5|Te={^M(w(u45+MTRv^Qt$>25vBJiFdcp-&lrEau~ibq&CG5)=+{#cPd%yRbL_L=^F z3MsoxvUd^w!V7;*dJkQPXwF1#Iq(+#$`!nxXA@^)mb9py)7(uAydS?&NErX*vYHPK z+*mzB)HN;}6i2Ct&e6koWIv|rH1K+FYAux(Jy!OS9J8{Rg34xi>#MR^8H&(n6m%I!fBk3UhC&Q&7p*8 z^J9r8x2OTIrP4W`4-V|(YfXLvk(sSMi%$?M&2PJ&zdC>I5&gZ+(wh8QI#GJDkiz|O zE0%L`B<`egUH@#@s|=O(@NO+kpn2s_?8x$=CCnbv~nz$?I^yX2TRTRMV@y6Ozq28;#H?k|566y%=6pNg zE4BOJx}6foZh)_dYkweeg?haGhCgNat6zZF)6eW+=d~uczLEQaO0;tJaYVV->T3I; zoy>B8Qy5e~O=Ae>{uHhh)^cYk`*t=>N)@@~-<#;tzWJ^?ysV;R;a|-m1?bnm`;yvE z@Tj(TI8U$tq=c30XJ$pQ( zYIjkB$0&XK_EJYfmz|llLd8!S?d2rfuG0_*Xbalj4;PR&{0EZ>S4-FF`@vsq*ljhaxmC3fvjB3JYzn7LfJwaHIatJOe{%6BHFs{3h$$z}cQ zF|8WCGb>rXeOZc8y%iHtx$dst60pVcFn&h;M^2n>U%w8v#NpY^2R}H;1b*9N;oMGY z6*gW$s?O1%;U8KVv%&r8Z?Dot#qnqoWT$w@{RY5dVk=soLq&1?kZ62V{T<4RE4A}u zI5$WtyV^h9GqILU_@bHMzf>llg@9zGd!MleqT~?qj#QJZZ%{l+k<8_YFIG&cxVSw1 zl$K*lWl(*PW%?77%P>a}1P4UF@G!+xp0~z&_#~bFHidxHGAPg!P+!7GWFA;oKKGuv z2Ddr#zfF&2jn<40#&yl31a3=6Ci+K`jxz;yXf0x0o^e$~5%`<-@|ON&8VC0;h+Jm& zzRGP>Jxda>3*^SMYXk+pT`0r~yC;V^dcANv^fuQ%`outOvEK(4Vh<7zm1euTyNP~s zoxN6;TC(>{K61>ESKA?uRJQ#Il0s{>!+*nySzjo8vgcs0LCB_a)?BAeU&T%3#G~R2V2@;O%#WwC{5)-GigiH13R&g``R=$8YEn^$-!g6P}Xj}9@y(#A)tPks-Fe1 zE5CWCy}$u}A5m(RxUlBJ&rN^WFqX#n){26VbMu8IQi|&3N~X9}$EBMTqGgcNDlS&y zVHjO-GC{3>9|nnqE13xQ(&pA?{>Wc0VF-bqAFlb`TOTvyuS|!;zm9Uk<2%H73#`op zJ9xB}$fICd-K3A6eXjzLvq{6{`t$R#{fS|x3kHZ*8EdGMiXYV7D99nE&N?ZN!P+*z z=uNkGcz!U-)7GjzPWzFuhJnGR-RL)_Z8b=WktW^GLNmH4>tV^dp_+sB@jLk;3l401 zp?xOK=_5Cdl28uYbt4+;L_2EWX@c!<@WX1DRPz^(>=9aEYM7%RVQABC<3v-Dhq&a| zvTYItw!rrQxtnv^E|{c1b?hvsNt^0YgOi7$`VS#|P3ABOc%52QQYgC!oVYoBn>}fh zX`0Y-D%|G1AaL{6BF%e`*n3`w5uoJt!YJ&&XQ^FU{TJO%!V(!Ptk%2-)BI?+;qqun z@RZWBoKu!vS}5LQy_onqp4Y%U41zcZ{9M{hcRzJArPE!8{klmOGH{SCY@X_BPe|{F zS^ryH)ay`_AE{6yiwf==InIUUyhKKTCU3PfJE|W)F`iH~d3xY- zfQkf<-TrQaYzZ*D=&?V|qKjfW@Pz@{j#xU&7UR2m+TE8UKJxhVJ(@gB2e>n+TZVeG z*84;!RJ?!&UjDdgw#L_kr5^-8(Z=-#(F0q2&T>nUtKI(&2IG8PZ&pNQm)4<9RkL;` zV4vI}8e09SF*XkJf7F;kn=QV5{F>zxB0dVDXKg1$8zpXdg#2@WV6+)=7`NoxBb6Kc zd}GQky+@%HJDxCoY&js_f7vCirq12ZY^m$wVS9`6TH&K9;IWJZ2-r&9eVwc3G!@P! z>Dunkt5PR;kck}(4a{+o#XIupax4(g5%^+trtj2O$3qsFz15GKnXmnpSG!css$!r= z-zXPk*_Bl{ZNJFqH!~?~iwZsVx9K?VRlT0lkeooL4uF~joS{B#QNLtUh-`z;uP}oV zMZ*@^DVyZoo+`@a=VCcq`xkvNKKbT%P+%ma46fe_j=K2dcs+zpnW0ZL%kW6{xmi6(+}?Tg<<{v8;+BzdNg%@weSS|nxIamVR!9`GW0$Aq zd>=&$58sEO{rThy$(a7LDxbZMG#({YUL~7h?knEsE{RVo+f%1Rx)L!ga)%Oz4*gkN z&5)8>UsGy+hinKw{qG#V?vaIMd^?IjOZu z7_ZjB<|&J$jpLlNqC0nr)Y?G?3_MZ`dP^QTtbSl_rNNER!}JHk;v|vAZF231MdSSk z3(<*)FhqMGb#UVf6eMNYe1?}x!CVmi(#uGlN#W3rPhy722_yaK)I{LFdQ4jQHR(Ne zAXA8xK8lCREsB_gTjl_p<+~9Wxm7&;^mPA*slWM?EI5kwk0YP=t46*4yDO=OYp;u< zc5tzDI3^K3zLfV`px}!CN$cA>Yc*#>LG2Flj-5pR?$*uBr)EI**tj>XdQFcVUGsp^ z&;~hNzrRwa0W?MjbtsVdqGz7u8v@k~Ua+M~PG#all6cKu8dmL30b7?^`Q^Dn-h$h)0k4euD|Cd$7@eCvOeuh`cr zi%`VRf-V7+=GQ1qJzF7=Uk2<_y8BlnWM8W{X`^Z3R>G8~3M{{FWOHt_s`Sc1DJfYF zbCnbKR|o%EZ&s%~bsm%14Vfh+vx07ZtxZ(5Ka+FSNbQN{7@H3q^>-3)c%*G27M;Z9 zHUpNfx=xphQQSw-fR`5$jfic*$H~|t*5Goa2LhO^UTj<(cIn#^0)>Pci@yDPimnKp zx-D#Q(YvY-^SFzIgwQE>rP1se1Nw-9E+|5RmsJY zaC|ewZYnNjCg(N>wmzN@QTjV8JrmF+QR^dq3VaF2O~KTXhmgQTFb zQg2KMsIg+pWVhjh`NcsQ2@zf33|Da|XsAHt`T1jdQvSJ! zT%E<;_!$l99ygFVM2Zf58*))6&a4iEA-v*;+3jRk;g7&7gijoz*mD09_S2QP>OleC zTlk5rm@8*~E*G!9oUSl@_YLa2`dgn6u)!OOhNFFDc#874_VSdKQ;sQ1pFXa*3z|sHJd8ebe+hn2qQC zy?65X$9f!rza{dOON}lR2SC4B?>!lOU|OogXVpia8LUnaeYlJm;@nYuW0IGZLV$%_ zsA2r4#Y~j`JY;z4KQO925i9uc%s#Bv?`r?@?{^c-7hFnx1flWv%5Y5l=Es?8PWj1r zBrS-qareEmL?oH`Tp+sIPKK*oPl={Ho{`XYfK;Qy{=lX*rPWg~a^0Z%UL4Nxd5RG-=2qU}a_o8|htH2YL_R)*Q0 z%x7ZLpha7rzf?)r=%f_7VkI(O1<2sSH#dn>@;-J*NU-hHmAlr%7BM7)8sha&TVjpq zL!f-?!m}$#FdZ8k+i->J>Zg|{G4;L`{tWc%_U9|knZfH?tD!hDDq0#iQ-=)8AvLErNFcD1pX@iVAt5tW#uNFQe?cS=qMpf%X{QhEP zu0aIl;ZkbS-e$NFrgOMAk!ST`XeKx~Gsil(WBGn3-Q_+|?xU`^W(aZFuQWfeF}E0G zNFfT;D?<+{5dohaZo>W_<|3d>B|Tv_dpFi)eW3ha?ENwI(ZNA&ei=H;P95Oj(2$O& zlTQIY#HK&L`3u=wAgu5@({c`379UhwCXc~^18XAV^ST~YSp@IVGpH>>Nr@xZOW14a zhND1Xa~+}Rx)>~am<7?3uK_vqjEto%*UQZwI21IjqMfo}=CTuPo)O7>48+A_@)q}j z!n8T9?~@4;SAT)RmwGOiVK=#K0pu}f4wJc0Y=4SBZr-KR4T(8)M5MQ~$5CXjf(>Ha zRW5>S<^$XuFct0iI;`1CGME`4$z5s=0xswh zVrr29W)jHjtV0p*ZVp3q^w~%3qF4)|_}UI{ft{jkT=uPK!Lj$*ZrRFu?=l1lFw0yG3YcAoifgUA^Enh18#+i2ug}gi#qR##Rf8I(ayLw znw^<1_KOfddIB5zG-~U99IXRW^5EAqLHO5uE}# zIZRW;`?!43T!#d((dvD&T3Y$jc}1k_cOdGnl=4Rg6B>kL>-=be5492$(Ir ztuE!){_LOyf^Ca;sHSUBeBlg(J}bs<+I2L4un!Xu7GALGE_|e{enZm}{p;Y*dDu~+ zd^eT<@1!IWIUtPcWIW5F?#FBOy+2}%h-!jAeRD`Pwo_U9G570Q3@y0cr*b&%Qv{1( zCW2z_elNdwda*mEV{2Qi5OQFT)PB1eTZ%RrjEsVvDCus_h5)lk2eGc5K*}sRd=L-T zg6>z60yba>mT(03<1a*gLLG-M?u3=`B@mg4q=42@78tTZMWMZn!9nnDBR^#lTr3lb zTk812q>;%NQ2I(AnM5l4Lnx_8gftccd`N1`qEHB=Apv(Adjn%xU^&PFDVWy*T|9kJ zX3zGm2~*#d&lY+Y`H#^}Wz!m-{KCTX@g2#RyRiZTm}}DKwE0gz_(Fx~^9+KvMKlr) zaxR9f0r3{~r}g4;EzAJ!RB=XMSXVs+e1ppOsy3j43!tQs*E_l(!#i1va0FK8$vldJ zE++LKd*JNZS}PTURzH5@ZR>K_n~rS;hec6!dNX?%w1H66$5f|E3X4)b@+SXL;j`0-Eh4m4I9p{&V#AX;O-8-l zpU#IkOWR|~R*XxDeNCmb1pFezDB&~&FI~jz*MVg0hxJT7i0Zc=Q8JqWh~**9n607$ z3>hPvb8_JRAPFSH$+S4bgI7em$hddsQS_ffu$^+XQcv-Uqo4k*wYTTgC{!*bDxQO3 zrxH9CrE18@8u6si|1EcfOy)cWvMwm`?bsOW0V`^UU1(@sURKnXSdr$em=(PKQe=bv zd{y!xCIY@=-hPyRU5lBjn@-lk2K++2(L15@K@8Eg zU#CFAWQSMfrc$UNh#sE1WK|Y&>gOv=m|gEaGn9J0ZJ{j(-h*m8#H2okSb)Ni08)rH zK%K%Y4BVedQ~4bHTNlx6i82(z{lk{t2(c$ls?qiAK z6sDw##@v~JVUV(zIM+1%DArE?w2ve89PO?;i1_jVq)?fr-BKR8%o;FrfRe*a+Mi|} zKp%^6kXo_s<)`maE^Hb*e8oQ3J_U>61I>9b^{?nzDiKiQ|Lru*Q)dJ#A%F#Of@?*~ z=-AZej2-V$qArNubEP6Lfh@#=27JHsT55N$rjVT_=#e)7FF1fFZd~4nF%PcG0;GM5 z_n%Qx{_}i%gy&NSovv5$8`EU5EpK06Cni`1OzLf!YQnSwwfyTthu$Xc3MrQAjhWFw0NS*89X^69-aT zJbcB;$>t0}zkNo(Ts0Sj74E84NL%j4KJ722_OBwXmPfae1by9P>wgI={=4g07jA&3uj=M;O++32X74dX zRe1vs|4oeovz16+cFR9rDqYMb#89gb?MxgXTH@WlAPu6QlceB{aP|lL+D-dq6W0qb zewaV+8cdrNH*45VmU<{T4LOs9E8#z$0bz$9HU{x}3i~)k+|+=uq(QEbOmYpMWG}{_ z#J!O2jDSXeZ!j$2eV^!}5#J8FXINML>)-H`r=Q^xQM)fNHfhF;-|a1Q@JVt@XR)9s z3@zXrf#}T58tNyWLef5TjCJtxiR7nyJH#4q6$~%n=u$&?`x*s>Zc{~w5gg08&ZC%V zKdq&<+0z+0U?Ic&=DkQ<$EZII(ES5yucVA&nm17$NNMO_pJGAKmOL2tJ6@tZUNTub zGd6kd)kEX!{FEpD!^aS8X_B8*k^2~caAh|Vc5|Ed$2JgPp^MJ4@0B5H%hgy7b^fm1 zXT0|h4pOiou4oA0-&-4}SOJnAs$YMLj7`w{z8C*R_w0vQYRNrQuYmj8^q)JZzEbZB zhXTR<`lL~rO)$NNV}>y3HOlqo*1v~P^ia@tfyg3>6I+aUaaJRvcAeSK!eRT8#6zq> z5X2uYg(uK{fQb9=W$(%j@?z~)JIc&K`R`HT(C_S#YWiKj30#P!A-<5`-%}J3B)kC_ z_L0L@r@n&ZQi^OTkk30L?IOXU;SqWb35^+#1e?%k7E{s~RGA##*M8^XPv611D_M^( z`mIR#D`CB6gBEe+Yc4Z`QY^T%@CK20e){S59aPiaj6ZYsxHYtvmjh$UUCfiI14wI& zq8_oY7ytuVC1hHnJQ+31|4|5rVdD_nl$3I&e+AoKhpBO;-hh1kC0 z(_BKnaAc+rh7R5w2l^hDj8E&Bzf+t93w3W?Q@h^3sF?B5LN_HLm5OpXlCF25sm9 zzo_N%v+9+svUAv+*qDRf{_bATvYo|M9yU^CBKQ)HzZdh>+|lv?j_56oHfCbP%YR$( zOq|wp2cT!u-5U`gF0>coK=2S5zIQqq0#%OH+**9Cz)^=tHimp(>v_U4f6!NB7FZ3h z*F}K=!ZT*QTR{L6k)gQtZRsUfog&=%uA94tBboTV^1r?Dw>>t*dvvyUX0@nfU)`T= zYaaI^ptvPE(yY36q~cB&hPj~pWsw2F@m;EH`K`IBCXOxyS5;Ssy{angh_GYBDcbSI z%-**4Y{!!u9aY`myJ5+K>bqFOpxh$oAXdKL?xIC0FW^sfno;J&K1~L1H-&~KJp>Uc zwnNIRV+UdpqeGM~mt6nPNz_yZ4Eu2qW%KzeM3f9Rj%Hxtul(bzr+Ox>S$6Yz>)I7v z>##%gzgd}YV3*9t06RH|)$6lYBjlDG3wd%w8m>I?y|w!E*43}0!VpK7bd|MTe?8)UeHY2 zLFQs0*-aov928akgSkMgsXz_3zOrcg&)Ep5x@UL2g+-*Kck-PD6KQ5DwRr`;XOgGT zugNKxg)CeGMxB`&x4=wBQiF{{fTit&tMLtnFcSi?+W z|Dq#itY3)MK;po;bdV)p5*9{9%A~1n2Mma#l645#Qa+pXuuS_DMy|0UtAs*2{#?k; zPY3sSdd;!~oD6`>srgDl5VS1D*mZ(>ab9`5b3zf#ioDKrlMSdiy?&4s;q|G= zcqC#FJHWC&QVq(N%@HA{D=p~zd-!BT1WU3bwi*K85NQO#zMu^kp-e)WatU!+4iqoD zdB>F)r-Ef6DFO?;^I!G;g^3J`SO;-DTFfnowcZu+_uch-_Tzrd!M3YYNg18rA_i(F zaIwA9n%PWCtgcK9$DL0tVW$qBK2p{YQ8hPf9j;k>SoR-rOi|A;zgNV`zjWgT87Vr}>%IyN-NO+>`n+=T{Q z8Nc?&WkXO7FK?V+_BVeCjy@X4cA>iSk$!-@;D7M~tfl>Xi*dtvk5C}}5S$RKBv}ba z6F!;eXCJaqIvDrOe2;(46 zQ~bEKuX}&A$p0UY_VHjh>)*9Y`@)!bvW@#A&P(LjdfhE_m=ZqA2j>c zPCwmZOO&aK{B_FLBAgVf9|FaYH-C9BH%*uw8eo{CA%x?ww3_i#n)}_T- z8k&ijgnPyHMSpCB=z}%dDs?6jb#Zw<74$Py%kzu@Ud$2znv z4t*?oV_Z(~%6tVWhLTNA^9zNwxDq$Yxh*+D$5s)IyFv7q4E8~=XKFv$xLEh(-yg6& zpB#&W`S{SUNnzE{&!d~<#HhLG3HnlWy5Bi%`D9vXxoSrHxFJN z#WJAS4k%LZn$Y-S_Xj{eV+T5NnG6|=`-=n9tX}+Ebe*3RM>g#$MEHn7ahqv8e|6Nf z1+Uxv5;Wg+PZSs{;YIMQDQTK$2JZI-iy6@zR$e078c7HqzzOtm;AcT`cGQ@A$`RLr z*@8mnY=pi8v;C?0{tA2SEdR+KSP#D%)IBI6P~7MJN-_D_LwNsBIT^1%lOX8@XtW?4 z*DJ7f8y*9E43&?!bRYL2dwJ$k>?9zUvgYn+j- zNu6HFzV5O1nvL93xh$D(#Fzg=m4_%PJV62*UN=Ac-&>7}`l;ao-DBlnfmF{z6OgQg zlSkm1n0KXrfXpRhY~+1tT^CADCCm~X$vK@6P}n&+MfRUY1k9A^Bt{eQy3*i*!~U|S z;n-t4n`Vtggi#8i^`q=4o+@&Qah(g&SyduAXeh4G1!hqH09d8p>|&z zYZeY$G7U?l^xlr|((g3bua!dKwaAD!*NWKA8_#M8E}5+*EZ*Qshwe(HrE z8_X@esN^j~v2$6D?x)HH0&UgPu?Oukr0NzPE*k=yT@&|Gl%84=EMM`$zW9$pRN5(H z&_=QKN5h`nD8AHmpo@k6*(#<9W3&h+8M_>fLTGZE#43}naPC2Y4B>q5uqHBF?-FDo zyD(yz+zw%NiF+Kt!=~O9D zfPlDH6y;Q(^YqR_L|zPMzb+HT_N$m;m-B-^u45zY_F6Hbqt7=J>rr2V%Sr!LOhAYr z!+!rt*F7*WRKi``D?Ua%LOy$PGZKz31Y@u2qNYmv6v9%`?uQN&t7jZw4HIKd(FCLi z(}3S@^M#B{Hz#yK%$QN7IAAOTXnoLC4E4a)Q4w$2wt9WOu#EpW(KZYejOVYbRjvrn&CKD&0fK$reNM%lKYl#W_8 zy?#jS<@6`wNk>^8&P1}U&OnK-hW$Y`Qq5_S3eeq?v$mkPg~(|>!E-UCMZD;kdqnah zLL;6z&1p`t&0qg|Q4`ZDDrr$*8TA1Dl64%PxjqS|spH=Ju?ayw5mFs;`@S<8U9B?H z!l2b;DehWCa|&yaPFE6m>Qyfsfy!mL$3m?tK=|6b8;T>ijsg_Mzn-eqxThL}Iz7W6 z0HrHh>GW);arrOneTq(`TD_Kp|Iuy`I5}S_4g1#mJn~F#8oRTQ`(M@_RE3vs*&i8K zq(EUd3KZE0g`W13tg@5tvF5J2R5qL^Q(+cAyPw~xz~(j(PpxFdtUDPYL<_Ri54bPd zOs#pO0k6IM$;2OvvFWYL!^v+b-VHe$BHUlrLJYFxf}dI%>Zcn!u-`X-Fmlc~CcKu_ z2t2bGn!IR7Jb&n{TTeZ8{6-x!^v(J~V6tv5d6D)J7n&i83tPqs~5^OCN{lW<~=s{ zixB#kYTpFD7e)090p+{vx_%(DSBWtTvBXm-e>jaor`VlU-9P(?pcZlYDVz7*hvO=; z(n%@rzI*ykIQ{?P_WwQnQEF-QnrxLP|p@)Ui z3P*jL$l1W3DwP+|_cDo%yYg&No7b&cTPDPb;AkiMcC~F7&m{IBp#zmnNUb@ln@?S; z>K$FRV=Yf;-*`DC3m{qR@OHy7!kX(wXp1LZu9AX&rGDhR%J=_@Dj^mnCqcRu_ zE@m{7W5?j8Wiac;UY0gLRxi(25}GtIcLTW=>X6YtnV9^mvzzo@Qk+wUSH5O>(qsSE zSoV$fRO&YdEqv}B`rm9#+_*PiO!dBp)fduN|71X|cV;O_xJ)&e^tM-=D`qs-VcE07 z@CUmfYA^4P?)*?Ob}I~@Q)1cd;H;| Date: Sun, 1 Oct 2023 10:07:24 -0400 Subject: [PATCH 42/59] Update aboutlib.version to v10.9.1 (#9971) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2b3431d1a..48ef5459f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -aboutlib_version = "10.9.0" +aboutlib_version = "10.9.1" okhttp_version = "5.0.0-alpha.11" shizuku_version = "12.2.0" sqlite = "2.3.1" From df332860b8fa1a4f873a7fa1d08c45e71cfb12ed Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 4 Oct 2023 22:28:50 -0400 Subject: [PATCH 43/59] Bump dependencies --- app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt | 1 + gradle.properties | 3 +-- gradle/androidx.versions.toml | 2 +- gradle/compose.versions.toml | 2 +- gradle/libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 1d67ab668..7b07c8521 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -151,6 +151,7 @@ class MainActivity : BaseActivity() { } // Draw edge-to-edge + // TODO: replace with ComponentActivity#enableEdgeToEdge WindowCompat.setDecorFitsSystemWindows(window, false) setComposeContent { diff --git a/gradle.properties b/gradle.properties index 8102dd176..282f16ede 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,5 +24,4 @@ kotlin.mpp.androidSourceSetLayoutVersion=2 android.useAndroidX=true android.defaults.buildfeatures.buildconfig=true -android.nonTransitiveRClass=false -#android.nonFinalResIds=false \ No newline at end of file +android.nonTransitiveRClass=false \ No newline at end of file diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index ec3244800..5c6aca3f9 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,5 +1,5 @@ [versions] -agp_version = "8.1.1" +agp_version = "8.1.2" lifecycle_version = "2.6.2" paging_version = "3.2.1" diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index dc18de785..26f0809d0 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -4,7 +4,7 @@ compose-bom = "2023.09.00-alpha02" accompanist = "0.33.1-alpha" [libraries] -activity = "androidx.activity:activity-compose:1.7.2" +activity = "androidx.activity:activity-compose:1.8.0" bom = { group = "dev.chrisbanes.compose", name = "compose-bom", version.ref = "compose-bom" } foundation = { module = "androidx.compose.foundation:foundation" } animation = { module = "androidx.compose.animation:animation" } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 48ef5459f..553060638 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ flowreactivenetwork = "ru.beryukhov:flowreactivenetwork:1.0.4" okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp_version" } okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp_version" } okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp_version" } -okio = "com.squareup.okio:okio:3.5.0" +okio = "com.squareup.okio:okio:3.6.0" conscrypt-android = "org.conscrypt:conscrypt-android:2.5.2" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac72c34e8..3fa8f862f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 7f0f67d75249033451f9e0fc841de6359ec28b69 Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 5 Oct 2023 09:33:34 -0400 Subject: [PATCH 44/59] Update social media icons --- app/build.gradle.kts | 1 - .../more/settings/screen/about/AboutScreen.kt | 26 +++--- .../presentation/reader/PageIndicatorText.kt | 2 - gradle/libs.versions.toml | 1 - .../presentation/core/icons/CustomIcons.kt | 7 ++ .../presentation/core/icons/Discord.kt | 77 +++++++++++++++++ .../presentation/core/icons/Facebook.kt | 54 ++++++++++++ .../presentation/core/icons/Github.kt | 59 +++++++++++++ .../presentation/core/icons/Reddit.kt | 85 +++++++++++++++++++ .../tachiyomi/presentation/core/icons/X.kt | 53 ++++++++++++ 10 files changed, 348 insertions(+), 17 deletions(-) create mode 100644 presentation-core/src/main/java/tachiyomi/presentation/core/icons/CustomIcons.kt create mode 100644 presentation-core/src/main/java/tachiyomi/presentation/core/icons/Discord.kt create mode 100644 presentation-core/src/main/java/tachiyomi/presentation/core/icons/Facebook.kt create mode 100644 presentation-core/src/main/java/tachiyomi/presentation/core/icons/Github.kt create mode 100644 presentation-core/src/main/java/tachiyomi/presentation/core/icons/Reddit.kt create mode 100644 presentation-core/src/main/java/tachiyomi/presentation/core/icons/X.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 93d48d8d4..5b9540486 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -240,7 +240,6 @@ dependencies { implementation(libs.aboutLibraries.compose) implementation(libs.bundles.voyager) implementation(libs.compose.materialmotion) - implementation(libs.compose.simpleicons) implementation(libs.swipe) // Logging diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt index af3835987..c12f3128e 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt @@ -23,12 +23,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow -import compose.icons.SimpleIcons -import compose.icons.simpleicons.Discord -import compose.icons.simpleicons.Facebook -import compose.icons.simpleicons.Github -import compose.icons.simpleicons.Reddit -import compose.icons.simpleicons.Twitter import eu.kanade.domain.ui.UiPreferences import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.more.LogoHeader @@ -53,6 +47,12 @@ import tachiyomi.domain.release.interactor.GetApplicationRelease import tachiyomi.presentation.core.components.LinkIcon import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.components.material.Scaffold +import tachiyomi.presentation.core.icons.CustomIcons +import tachiyomi.presentation.core.icons.Discord +import tachiyomi.presentation.core.icons.Facebook +import tachiyomi.presentation.core.icons.Github +import tachiyomi.presentation.core.icons.Reddit +import tachiyomi.presentation.core.icons.X import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.text.DateFormat @@ -181,27 +181,27 @@ object AboutScreen : Screen() { ) LinkIcon( label = "Discord", - icon = SimpleIcons.Discord, + icon = CustomIcons.Discord, url = "https://discord.gg/tachiyomi", ) LinkIcon( - label = "Twitter", - icon = SimpleIcons.Twitter, - url = "https://twitter.com/tachiyomiorg", + label = "X", + icon = CustomIcons.X, + url = "https://x.com/tachiyomiorg", ) LinkIcon( label = "Facebook", - icon = SimpleIcons.Facebook, + icon = CustomIcons.Facebook, url = "https://facebook.com/tachiyomiorg", ) LinkIcon( label = "Reddit", - icon = SimpleIcons.Reddit, + icon = CustomIcons.Reddit, url = "https://www.reddit.com/r/Tachiyomi", ) LinkIcon( label = "GitHub", - icon = SimpleIcons.Github, + icon = CustomIcons.Github, url = "https://github.com/tachiyomiorg", ) } diff --git a/app/src/main/java/eu/kanade/presentation/reader/PageIndicatorText.kt b/app/src/main/java/eu/kanade/presentation/reader/PageIndicatorText.kt index c97515fb1..69df2a727 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/PageIndicatorText.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/PageIndicatorText.kt @@ -6,12 +6,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.Stroke -import androidx.compose.ui.text.ExperimentalTextApi import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp -@OptIn(ExperimentalTextApi::class) @Composable fun PageIndicatorText( currentPage: Int, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 553060638..1ee77f26b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -58,7 +58,6 @@ photoview = "com.github.chrisbanes:PhotoView:2.3.0" directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" insetter = "dev.chrisbanes.insetter:insetter:0.6.1" compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.1.0" -compose-simpleicons = "br.com.devsrsouza.compose.icons.android:simple-icons:1.0.0" swipe = "me.saket.swipe:swipe:1.2.0" diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/icons/CustomIcons.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/CustomIcons.kt new file mode 100644 index 000000000..8c8661b85 --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/CustomIcons.kt @@ -0,0 +1,7 @@ +package tachiyomi.presentation.core.icons + +/** + * Icons imported from https://simpleicons.org using + * https://github.com/DevSrSouza/svg-to-compose + */ +object CustomIcons diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Discord.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Discord.kt new file mode 100644 index 000000000..f9c80ff8e --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Discord.kt @@ -0,0 +1,77 @@ +package tachiyomi.presentation.core.icons + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.unit.dp + +val CustomIcons.Discord: ImageVector + get() { + if (_discord != null) { + return _discord!! + } + _discord = Builder( + name = "Discord", defaultWidth = 24.0.dp, defaultHeight = 24.0.dp, + viewportWidth = 24.0f, viewportHeight = 24.0f, + ).apply { + path( + fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero, + ) { + moveTo(20.317f, 4.3698f) + arcToRelative(19.7913f, 19.7913f, 0.0f, false, false, -4.8851f, -1.5152f) + arcToRelative(0.0741f, 0.0741f, 0.0f, false, false, -0.0785f, 0.0371f) + curveToRelative(-0.211f, 0.3753f, -0.4447f, 0.8648f, -0.6083f, 1.2495f) + curveToRelative(-1.8447f, -0.2762f, -3.68f, -0.2762f, -5.4868f, 0.0f) + curveToRelative(-0.1636f, -0.3933f, -0.4058f, -0.8742f, -0.6177f, -1.2495f) + arcToRelative(0.077f, 0.077f, 0.0f, false, false, -0.0785f, -0.037f) + arcToRelative(19.7363f, 19.7363f, 0.0f, false, false, -4.8852f, 1.515f) + arcToRelative(0.0699f, 0.0699f, 0.0f, false, false, -0.0321f, 0.0277f) + curveTo(0.5334f, 9.0458f, -0.319f, 13.5799f, 0.0992f, 18.0578f) + arcToRelative(0.0824f, 0.0824f, 0.0f, false, false, 0.0312f, 0.0561f) + curveToRelative(2.0528f, 1.5076f, 4.0413f, 2.4228f, 5.9929f, 3.0294f) + arcToRelative(0.0777f, 0.0777f, 0.0f, false, false, 0.0842f, -0.0276f) + curveToRelative(0.4616f, -0.6304f, 0.8731f, -1.2952f, 1.226f, -1.9942f) + arcToRelative(0.076f, 0.076f, 0.0f, false, false, -0.0416f, -0.1057f) + curveToRelative(-0.6528f, -0.2476f, -1.2743f, -0.5495f, -1.8722f, -0.8923f) + arcToRelative(0.077f, 0.077f, 0.0f, false, true, -0.0076f, -0.1277f) + curveToRelative(0.1258f, -0.0943f, 0.2517f, -0.1923f, 0.3718f, -0.2914f) + arcToRelative(0.0743f, 0.0743f, 0.0f, false, true, 0.0776f, -0.0105f) + curveToRelative(3.9278f, 1.7933f, 8.18f, 1.7933f, 12.0614f, 0.0f) + arcToRelative(0.0739f, 0.0739f, 0.0f, false, true, 0.0785f, 0.0095f) + curveToRelative(0.1202f, 0.099f, 0.246f, 0.1981f, 0.3728f, 0.2924f) + arcToRelative(0.077f, 0.077f, 0.0f, false, true, -0.0066f, 0.1276f) + arcToRelative(12.2986f, 12.2986f, 0.0f, false, true, -1.873f, 0.8914f) + arcToRelative(0.0766f, 0.0766f, 0.0f, false, false, -0.0407f, 0.1067f) + curveToRelative(0.3604f, 0.698f, 0.7719f, 1.3628f, 1.225f, 1.9932f) + arcToRelative(0.076f, 0.076f, 0.0f, false, false, 0.0842f, 0.0286f) + curveToRelative(1.961f, -0.6067f, 3.9495f, -1.5219f, 6.0023f, -3.0294f) + arcToRelative(0.077f, 0.077f, 0.0f, false, false, 0.0313f, -0.0552f) + curveToRelative(0.5004f, -5.177f, -0.8382f, -9.6739f, -3.5485f, -13.6604f) + arcToRelative(0.061f, 0.061f, 0.0f, false, false, -0.0312f, -0.0286f) + close() + moveTo(8.02f, 15.3312f) + curveToRelative(-1.1825f, 0.0f, -2.1569f, -1.0857f, -2.1569f, -2.419f) + curveToRelative(0.0f, -1.3332f, 0.9555f, -2.4189f, 2.157f, -2.4189f) + curveToRelative(1.2108f, 0.0f, 2.1757f, 1.0952f, 2.1568f, 2.419f) + curveToRelative(0.0f, 1.3332f, -0.9555f, 2.4189f, -2.1569f, 2.4189f) + close() + moveTo(15.9948f, 15.3312f) + curveToRelative(-1.1825f, 0.0f, -2.1569f, -1.0857f, -2.1569f, -2.419f) + curveToRelative(0.0f, -1.3332f, 0.9554f, -2.4189f, 2.1569f, -2.4189f) + curveToRelative(1.2108f, 0.0f, 2.1757f, 1.0952f, 2.1568f, 2.419f) + curveToRelative(0.0f, 1.3332f, -0.946f, 2.4189f, -2.1568f, 2.4189f) + close() + } + } + .build() + return _discord!! + } + +private var _discord: ImageVector? = null diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Facebook.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Facebook.kt new file mode 100644 index 000000000..1bb4bda34 --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Facebook.kt @@ -0,0 +1,54 @@ +package tachiyomi.presentation.core.icons + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.unit.dp + +val CustomIcons.Facebook: ImageVector + get() { + if (_facebook != null) { + return _facebook!! + } + _facebook = Builder( + name = "Facebook", defaultWidth = 24.0.dp, defaultHeight = 24.0.dp, + viewportWidth = 24.0f, viewportHeight = 24.0f, + ).apply { + path( + fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero, + ) { + moveTo(24.0f, 12.073f) + curveToRelative(0.0f, -6.627f, -5.373f, -12.0f, -12.0f, -12.0f) + reflectiveCurveToRelative(-12.0f, 5.373f, -12.0f, 12.0f) + curveToRelative(0.0f, 5.99f, 4.388f, 10.954f, 10.125f, 11.854f) + verticalLineToRelative(-8.385f) + horizontalLineTo(7.078f) + verticalLineToRelative(-3.47f) + horizontalLineToRelative(3.047f) + verticalLineTo(9.43f) + curveToRelative(0.0f, -3.007f, 1.792f, -4.669f, 4.533f, -4.669f) + curveToRelative(1.312f, 0.0f, 2.686f, 0.235f, 2.686f, 0.235f) + verticalLineToRelative(2.953f) + horizontalLineTo(15.83f) + curveToRelative(-1.491f, 0.0f, -1.956f, 0.925f, -1.956f, 1.874f) + verticalLineToRelative(2.25f) + horizontalLineToRelative(3.328f) + lineToRelative(-0.532f, 3.47f) + horizontalLineToRelative(-2.796f) + verticalLineToRelative(8.385f) + curveTo(19.612f, 23.027f, 24.0f, 18.062f, 24.0f, 12.073f) + close() + } + } + .build() + return _facebook!! + } + +private var _facebook: ImageVector? = null diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Github.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Github.kt new file mode 100644 index 000000000..25d16b5b9 --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Github.kt @@ -0,0 +1,59 @@ +package tachiyomi.presentation.core.icons + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.unit.dp + +val CustomIcons.Github: ImageVector + get() { + if (_github != null) { + return _github!! + } + _github = Builder( + name = "Github", defaultWidth = 24.0.dp, defaultHeight = 24.0.dp, + viewportWidth = 24.0f, viewportHeight = 24.0f, + ).apply { + path( + fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero, + ) { + moveTo(12.0f, 0.297f) + curveToRelative(-6.63f, 0.0f, -12.0f, 5.373f, -12.0f, 12.0f) + curveToRelative(0.0f, 5.303f, 3.438f, 9.8f, 8.205f, 11.385f) + curveToRelative(0.6f, 0.113f, 0.82f, -0.258f, 0.82f, -0.577f) + curveToRelative(0.0f, -0.285f, -0.01f, -1.04f, -0.015f, -2.04f) + curveToRelative(-3.338f, 0.724f, -4.042f, -1.61f, -4.042f, -1.61f) + curveTo(4.422f, 18.07f, 3.633f, 17.7f, 3.633f, 17.7f) + curveToRelative(-1.087f, -0.744f, 0.084f, -0.729f, 0.084f, -0.729f) + curveToRelative(1.205f, 0.084f, 1.838f, 1.236f, 1.838f, 1.236f) + curveToRelative(1.07f, 1.835f, 2.809f, 1.305f, 3.495f, 0.998f) + curveToRelative(0.108f, -0.776f, 0.417f, -1.305f, 0.76f, -1.605f) + curveToRelative(-2.665f, -0.3f, -5.466f, -1.332f, -5.466f, -5.93f) + curveToRelative(0.0f, -1.31f, 0.465f, -2.38f, 1.235f, -3.22f) + curveToRelative(-0.135f, -0.303f, -0.54f, -1.523f, 0.105f, -3.176f) + curveToRelative(0.0f, 0.0f, 1.005f, -0.322f, 3.3f, 1.23f) + curveToRelative(0.96f, -0.267f, 1.98f, -0.399f, 3.0f, -0.405f) + curveToRelative(1.02f, 0.006f, 2.04f, 0.138f, 3.0f, 0.405f) + curveToRelative(2.28f, -1.552f, 3.285f, -1.23f, 3.285f, -1.23f) + curveToRelative(0.645f, 1.653f, 0.24f, 2.873f, 0.12f, 3.176f) + curveToRelative(0.765f, 0.84f, 1.23f, 1.91f, 1.23f, 3.22f) + curveToRelative(0.0f, 4.61f, -2.805f, 5.625f, -5.475f, 5.92f) + curveToRelative(0.42f, 0.36f, 0.81f, 1.096f, 0.81f, 2.22f) + curveToRelative(0.0f, 1.606f, -0.015f, 2.896f, -0.015f, 3.286f) + curveToRelative(0.0f, 0.315f, 0.21f, 0.69f, 0.825f, 0.57f) + curveTo(20.565f, 22.092f, 24.0f, 17.592f, 24.0f, 12.297f) + curveToRelative(0.0f, -6.627f, -5.373f, -12.0f, -12.0f, -12.0f) + } + } + .build() + return _github!! + } + +private var _github: ImageVector? = null diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Reddit.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Reddit.kt new file mode 100644 index 000000000..efed17f01 --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/Reddit.kt @@ -0,0 +1,85 @@ +package tachiyomi.presentation.core.icons + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.unit.dp + +val CustomIcons.Reddit: ImageVector + get() { + if (_reddit != null) { + return _reddit!! + } + _reddit = Builder( + name = "Reddit", defaultWidth = 24.0.dp, defaultHeight = 24.0.dp, + viewportWidth = 24.0f, viewportHeight = 24.0f, + ).apply { + path( + fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero, + ) { + moveTo(12.0f, 0.0f) + arcTo(12.0f, 12.0f, 0.0f, false, false, 0.0f, 12.0f) + arcToRelative(12.0f, 12.0f, 0.0f, false, false, 12.0f, 12.0f) + arcToRelative(12.0f, 12.0f, 0.0f, false, false, 12.0f, -12.0f) + arcTo(12.0f, 12.0f, 0.0f, false, false, 12.0f, 0.0f) + close() + moveTo(17.01f, 4.744f) + curveToRelative(0.688f, 0.0f, 1.25f, 0.561f, 1.25f, 1.249f) + arcToRelative(1.25f, 1.25f, 0.0f, false, true, -2.498f, 0.056f) + lineToRelative(-2.597f, -0.547f) + lineToRelative(-0.8f, 3.747f) + curveToRelative(1.824f, 0.07f, 3.48f, 0.632f, 4.674f, 1.488f) + curveToRelative(0.308f, -0.309f, 0.73f, -0.491f, 1.207f, -0.491f) + curveToRelative(0.968f, 0.0f, 1.754f, 0.786f, 1.754f, 1.754f) + curveToRelative(0.0f, 0.716f, -0.435f, 1.333f, -1.01f, 1.614f) + arcToRelative(3.111f, 3.111f, 0.0f, false, true, 0.042f, 0.52f) + curveToRelative(0.0f, 2.694f, -3.13f, 4.87f, -7.004f, 4.87f) + curveToRelative(-3.874f, 0.0f, -7.004f, -2.176f, -7.004f, -4.87f) + curveToRelative(0.0f, -0.183f, 0.015f, -0.366f, 0.043f, -0.534f) + arcTo(1.748f, 1.748f, 0.0f, false, true, 4.028f, 12.0f) + curveToRelative(0.0f, -0.968f, 0.786f, -1.754f, 1.754f, -1.754f) + curveToRelative(0.463f, 0.0f, 0.898f, 0.196f, 1.207f, 0.49f) + curveToRelative(1.207f, -0.883f, 2.878f, -1.43f, 4.744f, -1.487f) + lineToRelative(0.885f, -4.182f) + arcToRelative(0.342f, 0.342f, 0.0f, false, true, 0.14f, -0.197f) + arcToRelative(0.35f, 0.35f, 0.0f, false, true, 0.238f, -0.042f) + lineToRelative(2.906f, 0.617f) + arcToRelative(1.214f, 1.214f, 0.0f, false, true, 1.108f, -0.701f) + close() + moveTo(9.25f, 12.0f) + curveTo(8.561f, 12.0f, 8.0f, 12.562f, 8.0f, 13.25f) + curveToRelative(0.0f, 0.687f, 0.561f, 1.248f, 1.25f, 1.248f) + curveToRelative(0.687f, 0.0f, 1.248f, -0.561f, 1.248f, -1.249f) + curveToRelative(0.0f, -0.688f, -0.561f, -1.249f, -1.249f, -1.249f) + close() + moveTo(14.75f, 12.0f) + curveToRelative(-0.687f, 0.0f, -1.248f, 0.561f, -1.248f, 1.25f) + curveToRelative(0.0f, 0.687f, 0.561f, 1.248f, 1.249f, 1.248f) + curveToRelative(0.688f, 0.0f, 1.249f, -0.561f, 1.249f, -1.249f) + curveToRelative(0.0f, -0.687f, -0.562f, -1.249f, -1.25f, -1.249f) + close() + moveTo(9.284f, 15.99f) + arcToRelative(0.327f, 0.327f, 0.0f, false, false, -0.231f, 0.094f) + arcToRelative(0.33f, 0.33f, 0.0f, false, false, 0.0f, 0.463f) + curveToRelative(0.842f, 0.842f, 2.484f, 0.913f, 2.961f, 0.913f) + curveToRelative(0.477f, 0.0f, 2.105f, -0.056f, 2.961f, -0.913f) + arcToRelative(0.361f, 0.361f, 0.0f, false, false, 0.029f, -0.463f) + arcToRelative(0.33f, 0.33f, 0.0f, false, false, -0.464f, 0.0f) + curveToRelative(-0.547f, 0.533f, -1.684f, 0.73f, -2.512f, 0.73f) + curveToRelative(-0.828f, 0.0f, -1.979f, -0.196f, -2.512f, -0.73f) + arcToRelative(0.326f, 0.326f, 0.0f, false, false, -0.232f, -0.095f) + close() + } + } + .build() + return _reddit!! + } + +private var _reddit: ImageVector? = null diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/icons/X.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/X.kt new file mode 100644 index 000000000..054030d03 --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/icons/X.kt @@ -0,0 +1,53 @@ +package tachiyomi.presentation.core.icons + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.unit.dp + +val CustomIcons.X: ImageVector + get() { + if (_x != null) { + return _x!! + } + _x = Builder( + name = "X", defaultWidth = 24.0.dp, defaultHeight = 24.0.dp, + viewportWidth = + 24.0f, + viewportHeight = 24.0f, + ).apply { + path( + fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero, + ) { + moveTo(18.901f, 1.153f) + horizontalLineToRelative(3.68f) + lineToRelative(-8.04f, 9.19f) + lineTo(24.0f, 22.846f) + horizontalLineToRelative(-7.406f) + lineToRelative(-5.8f, -7.584f) + lineToRelative(-6.638f, 7.584f) + horizontalLineTo(0.474f) + lineToRelative(8.6f, -9.83f) + lineTo(0.0f, 1.154f) + horizontalLineToRelative(7.594f) + lineToRelative(5.243f, 6.932f) + close() + moveTo(17.61f, 20.644f) + horizontalLineToRelative(2.039f) + lineTo(6.486f, 3.24f) + horizontalLineTo(4.298f) + close() + } + } + .build() + return _x!! + } + +private var _x: ImageVector? = null From 78aa50bb350b0142a3e0407b3d2f6084b9c1a835 Mon Sep 17 00:00:00 2001 From: LooKeR Date: Sat, 7 Oct 2023 03:54:43 +0530 Subject: [PATCH 45/59] Reduce recomposition of MangaHeader (#9985) * Reduce recomposition of MangaHeader * Reuse `Modifier` for `Tags` Reference: https://developer.android.com/jetpack/compose/modifiers#reusing-modifiers * Don't recalculate Read State on recomposition * Fix Linting issue * Optimize chapter state calculations --- .../kanade/presentation/manga/MangaScreen.kt | 96 +++++++++++++------ .../manga/components/MangaInfoHeader.kt | 6 +- 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt index 65963cef3..82c266f65 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -268,8 +268,14 @@ private fun MangaScreenSmallImpl( val chapters = remember(state) { state.processedChapters } + val isAnySelected by remember { + derivedStateOf { + chapters.fastAny { it.selected } + } + } + val internalOnBackPressed = { - if (chapters.fastAny { it.selected }) { + if (isAnySelected) { onAllChapterSelected(false) } else { onBackClicked() @@ -279,17 +285,22 @@ private fun MangaScreenSmallImpl( Scaffold( topBar = { - val firstVisibleItemIndex by remember { - derivedStateOf { chapterListState.firstVisibleItemIndex } + val selectedChapterCount: Int = remember(chapters) { + chapters.count { it.selected } } - val firstVisibleItemScrollOffset by remember { - derivedStateOf { chapterListState.firstVisibleItemScrollOffset } + val isFirstItemVisible by remember { + derivedStateOf { chapterListState.firstVisibleItemIndex == 0 } + } + val isFirstItemScrolled by remember { + derivedStateOf { chapterListState.firstVisibleItemScrollOffset > 0 } } val animatedTitleAlpha by animateFloatAsState( - if (firstVisibleItemIndex > 0) 1f else 0f, + if (!isFirstItemVisible) 1f else 0f, + label = "Top Bar Title", ) val animatedBgAlpha by animateFloatAsState( - if (firstVisibleItemIndex > 0 || firstVisibleItemScrollOffset > 0) 1f else 0f, + if (!isFirstItemVisible || isFirstItemScrolled) 1f else 0f, + label = "Top Bar Background", ) MangaToolbar( title = state.manga.title, @@ -303,14 +314,17 @@ private fun MangaScreenSmallImpl( onClickEditCategory = onEditCategoryClicked, onClickRefresh = onRefresh, onClickMigrate = onMigrateClicked, - actionModeCounter = chapters.count { it.selected }, + actionModeCounter = selectedChapterCount, onSelectAll = { onAllChapterSelected(true) }, onInvertSelection = { onInvertSelection() }, ) }, bottomBar = { + val selectedChapters = remember(chapters) { + chapters.filter { it.selected } + } SharedMangaBottomActionMenu( - selected = chapters.filter { it.selected }, + selected = selectedChapters, onMultiBookmarkClicked = onMultiBookmarkClicked, onMultiMarkAsReadClicked = onMultiMarkAsReadClicked, onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked, @@ -321,19 +335,20 @@ private fun MangaScreenSmallImpl( }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, floatingActionButton = { + val isFABVisible = remember(chapters) { + chapters.fastAny { !it.chapter.read } && !isAnySelected + } AnimatedVisibility( - visible = chapters.fastAny { !it.chapter.read } && chapters.fastAll { !it.selected }, + visible = isFABVisible, enter = fadeIn(), exit = fadeOut(), ) { ExtendedFloatingActionButton( text = { - val id = if (state.chapters.fastAny { it.chapter.read }) { - R.string.action_resume - } else { - R.string.action_start + val isReading = remember(state.chapters) { + state.chapters.fastAny { it.chapter.read } } - Text(text = stringResource(id)) + Text(text = stringResource(if (isReading) R.string.action_resume else R.string.action_start)) }, icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) }, onClick = onContinueReading, @@ -347,7 +362,7 @@ private fun MangaScreenSmallImpl( PullRefresh( refreshing = state.isRefreshingData, onRefresh = onRefresh, - enabled = chapters.fastAll { !it.selected }, + enabled = !isAnySelected, indicatorPadding = WindowInsets.systemBars.only(WindowInsetsSides.Top).asPaddingValues(), ) { val layoutDirection = LocalLayoutDirection.current @@ -419,10 +434,13 @@ private fun MangaScreenSmallImpl( key = MangaScreenItem.CHAPTER_HEADER, contentType = MangaScreenItem.CHAPTER_HEADER, ) { + val missingChapterCount = remember(chapters) { + chapters.map { it.chapter.chapterNumber }.missingChaptersCount() + } ChapterHeader( - enabled = chapters.fastAll { !it.selected }, + enabled = !isAnySelected, chapterCount = chapters.size, - missingChapterCount = chapters.map { it.chapter.chapterNumber }.missingChaptersCount(), + missingChapterCount = missingChapterCount, onClick = onFilterClicked, ) } @@ -500,12 +518,18 @@ fun MangaScreenLargeImpl( val chapters = remember(state) { state.processedChapters } + val isAnySelected by remember { + derivedStateOf { + chapters.fastAny { it.selected } + } + } + val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues() var topBarHeight by remember { mutableIntStateOf(0) } PullRefresh( refreshing = state.isRefreshingData, onRefresh = onRefresh, - enabled = chapters.fastAll { !it.selected }, + enabled = !isAnySelected, indicatorPadding = PaddingValues( start = insetPadding.calculateStartPadding(layoutDirection), top = with(density) { topBarHeight.toDp() }, @@ -515,7 +539,7 @@ fun MangaScreenLargeImpl( val chapterListState = rememberLazyListState() val internalOnBackPressed = { - if (chapters.fastAny { it.selected }) { + if (isAnySelected) { onAllChapterSelected(false) } else { onBackClicked() @@ -525,10 +549,13 @@ fun MangaScreenLargeImpl( Scaffold( topBar = { + val selectedChapterCount = remember(chapters) { + chapters.count { it.selected } + } MangaToolbar( modifier = Modifier.onSizeChanged { topBarHeight = it.height }, title = state.manga.title, - titleAlphaProvider = { if (chapters.fastAny { it.selected }) 1f else 0f }, + titleAlphaProvider = { if (isAnySelected) 1f else 0f }, backgroundAlphaProvider = { 1f }, hasFilters = state.manga.chaptersFiltered(), onBackClicked = internalOnBackPressed, @@ -538,7 +565,7 @@ fun MangaScreenLargeImpl( onClickEditCategory = onEditCategoryClicked, onClickRefresh = onRefresh, onClickMigrate = onMigrateClicked, - actionModeCounter = chapters.count { it.selected }, + actionModeCounter = selectedChapterCount, onSelectAll = { onAllChapterSelected(true) }, onInvertSelection = { onInvertSelection() }, ) @@ -548,8 +575,11 @@ fun MangaScreenLargeImpl( modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.BottomEnd, ) { + val selectedChapters = remember(chapters) { + chapters.filter { it.selected } + } SharedMangaBottomActionMenu( - selected = chapters.filter { it.selected }, + selected = selectedChapters, onMultiBookmarkClicked = onMultiBookmarkClicked, onMultiMarkAsReadClicked = onMultiMarkAsReadClicked, onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked, @@ -561,19 +591,20 @@ fun MangaScreenLargeImpl( }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, floatingActionButton = { + val isFABVisible = remember(chapters) { + chapters.fastAny { !it.chapter.read } && !isAnySelected + } AnimatedVisibility( - visible = chapters.fastAny { !it.chapter.read } && chapters.fastAll { !it.selected }, + visible = isFABVisible, enter = fadeIn(), exit = fadeOut(), ) { ExtendedFloatingActionButton( text = { - val id = if (state.chapters.fastAny { it.chapter.read }) { - R.string.action_resume - } else { - R.string.action_start + val isReading = remember(state.chapters) { + state.chapters.fastAny { it.chapter.read } } - Text(text = stringResource(id)) + Text(text = stringResource(if (isReading) R.string.action_resume else R.string.action_start)) }, icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) }, onClick = onContinueReading, @@ -644,10 +675,13 @@ fun MangaScreenLargeImpl( key = MangaScreenItem.CHAPTER_HEADER, contentType = MangaScreenItem.CHAPTER_HEADER, ) { + val missingChapterCount = remember(chapters) { + chapters.map { it.chapter.chapterNumber }.missingChaptersCount() + } ChapterHeader( - enabled = chapters.fastAll { !it.selected }, + enabled = !isAnySelected, chapterCount = chapters.size, - missingChapterCount = chapters.map { it.chapter.chapterNumber }.missingChaptersCount(), + missingChapterCount = missingChapterCount, onClick = onFilterButtonClicked, ) } diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt index 5e0efe42b..4d9e320fe 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt @@ -286,7 +286,7 @@ fun ExpandableMangaDescription( ) { tags.forEach { TagsChip( - modifier = Modifier.padding(vertical = 4.dp), + modifier = DefaultTagChipModifier, text = it, onClick = { tagSelected = it @@ -302,7 +302,7 @@ fun ExpandableMangaDescription( ) { items(items = tags) { TagsChip( - modifier = Modifier.padding(vertical = 4.dp), + modifier = DefaultTagChipModifier, text = it, onClick = { tagSelected = it @@ -654,6 +654,8 @@ private fun MangaSummary( } } +private val DefaultTagChipModifier = Modifier.padding(vertical = 4.dp) + @Composable private fun TagsChip( text: String, From 6462472d16801fdb8dd32967907ac87f8b99a8a0 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sat, 7 Oct 2023 15:44:30 +0200 Subject: [PATCH 46/59] Translations update from Hosted Weblate (#9957) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Weblate translations Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ar/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cs/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/it/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ja/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pl/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sc/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sk/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/th/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/ Translation: Tachiyomi/Tachiyomi 0.x Co-authored-by: Ajeje Brazorf Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> Co-authored-by: Ali Aljishi Co-authored-by: Dan Co-authored-by: Dexroneum Co-authored-by: Eduard Ereza Martínez Co-authored-by: Giorgio Sanna Co-authored-by: ID-86 Co-authored-by: InfinityDouki56 Co-authored-by: Jendrej Co-authored-by: Lyfja Co-authored-by: Lzmxya Co-authored-by: Milan Šalka Co-authored-by: Milo Ivir Co-authored-by: Pitpe11 Co-authored-by: Swyter Co-authored-by: Uzuki Shimamura Co-authored-by: Yesaya Kefin Irli Co-authored-by: abc0922001 Co-authored-by: altinat Co-authored-by: bapeey --- i18n/src/main/res/values-ar/strings.xml | 14 ++++--- i18n/src/main/res/values-b+es+419/strings.xml | 26 +++++++------ i18n/src/main/res/values-ca/strings.xml | 2 + i18n/src/main/res/values-cs/strings.xml | 12 +++--- i18n/src/main/res/values-de/strings.xml | 14 ++++--- i18n/src/main/res/values-el/strings.xml | 10 +++-- i18n/src/main/res/values-es/strings.xml | 10 +++-- i18n/src/main/res/values-fil/strings.xml | 2 + i18n/src/main/res/values-hr/strings.xml | 26 +++++++------ i18n/src/main/res/values-in/strings.xml | 15 +++++--- i18n/src/main/res/values-it/strings.xml | 12 +++--- i18n/src/main/res/values-ja/strings.xml | 14 ++++--- i18n/src/main/res/values-pl/strings.xml | 2 +- i18n/src/main/res/values-pt-rBR/strings.xml | 12 +++--- i18n/src/main/res/values-ru/strings.xml | 10 +++-- i18n/src/main/res/values-sc/strings.xml | 37 +++++++++++++------ i18n/src/main/res/values-sk/strings.xml | 6 +-- i18n/src/main/res/values-th/strings.xml | 14 ++++--- i18n/src/main/res/values-uk/strings.xml | 12 +++--- i18n/src/main/res/values-zh-rTW/strings.xml | 14 ++++--- 20 files changed, 158 insertions(+), 106 deletions(-) diff --git a/i18n/src/main/res/values-ar/strings.xml b/i18n/src/main/res/values-ar/strings.xml index 399f5c0da..09d7ac2fd 100644 --- a/i18n/src/main/res/values-ar/strings.xml +++ b/i18n/src/main/res/values-ar/strings.xml @@ -127,7 +127,7 @@ من الفصل الرابع قبل اﻷخير من الفصل الخامس قبل اﻷخير تنزيل الفصول الجديدة - الخدمات + المتتبِّعات إنشاء نسخة إحتياطية يمكن استخدامها لإستعادة المكتبة الحالية إستعادة النسخة الإحتياطية @@ -438,7 +438,7 @@ المصادر المفقودة: النسخة الإحتياطية لا تحتوي على أيّة إدخالات المكتبة. ملفُّ النسخ الاحتياطيِّ غير صالح - مزامنة أحاديّة لتحديث تقدم الفصول في خدمات التتبع. قم بإعداد التتبع الخاص للإدخالات محدّدة من زر التتبع الخاص بها. + مزامنة أحادية تُحدِّث قراءة الفصول في المتتبعات الخارجية، ولك تعيين التتبِّع لكلِّ مدخلة على حدى، وذلك من زرِّ التتبع فيهم. ليست هذه الإضافة من القائمة الرسمية. غير رسمي تحقق من وجود غلاف جديد وتفاصيل جديدة عند تحديث المكتبة @@ -622,8 +622,8 @@ جار تحديث المكتبة…( (%2$d) / (%1$d) ) تقوم بعض الشركات المصنعة بوضع قيود إضافية على التطبيقات التي قد تقضي على الخدمات التي تعمل في الخلفية. يحتوي هذا الموقع على مزيد من المعلومات حول كيفية إصلاحه. قد لا يعمل النسخ الاحتياطيُّ أو الاستعادة إن عطِّلت أمثَلَة MIUI. - الخدمات التي تقدم ميزات محسنة لأجل مصادر معينه. الإدخالات سوف يتم تتبعها عندما يتم إضافتها الي المكتبة. - خدمات محسَّنة + يُحسِّن مصادر معينة، وتُتابَع المدخلات حال إضافتها للمكتبة. + المتتبِّعات المحسَّنة اليوم المصادقة لتأكيد التغيير الافتراضي @@ -644,7 +644,7 @@ ساعد بالترجمة واجهة مستخدم الجهاز اللوحي الفئات المستثناة - المثبت + المثبِّت إجمالي الإدخالات تحذير اللغة @@ -874,7 +874,7 @@ وُجدت نتائج تعذَّر إنشاء ملفِّ نسخ احتياطيِّ مرخَّصة - لا فصول - ولوج التتبع + ولوج المتتبِّع أُفسد فهرس التنزيلات اضغط هنا تتحرَّ كلاودفلير لا اتصال بالإنترنت @@ -882,4 +882,6 @@ لم نصل %s افتح %s انقل السلسلة للقعر + التوقيت النسبي + «%1$s» بدلًا عن «%2$s» \ No newline at end of file diff --git a/i18n/src/main/res/values-b+es+419/strings.xml b/i18n/src/main/res/values-b+es+419/strings.xml index ede476a22..8f4131c86 100644 --- a/i18n/src/main/res/values-b+es+419/strings.xml +++ b/i18n/src/main/res/values-b+es+419/strings.xml @@ -83,8 +83,8 @@ Restaurar copia de seguridad Se puede utilizar para restaurar la biblioteca actual Crear copia de seguridad - Sincronización unidireccional para actualizar el progreso del capítulo en los servicios de sincronización. Configure el seguimiento de las entradas de manga individuales desde su botón de seguimiento. - Servicios + Sincronización unidireccional para actualizar el progreso del capítulo en servicios de sincronización externos. Configure el seguimiento de las entradas de manga individuales desde su botón de seguimiento. + Rastreadores Actualizar el progreso después de leer Descargar capítulos nuevos Quinto al último capítulo @@ -107,7 +107,7 @@ Forzar horizontal Forzar vertical Libre - Tipo de rotación predeterminado + Rotación predeterminada Rápido Normal Sin animación @@ -159,11 +159,11 @@ Animar las transiciones de página Mostrar contenido en el área recortada Pantalla completa - Esta extensión no es de la lista oficial de extensiones de Tachiyomi. + Esta extensión no es de la lista oficial. Esta extensión ya no está disponible. Esta puede no funcionar apropiadamente y puede causar problemas en la aplicación. Es recomendable desintalar. Esta extensión fue firmada por una fuente no certificada y no fue activada. \n -\nUna extensión maliciosa puede leer cualquier credencial de inicio guardada en Tachiyomi o ejecutar código arbitrario. +\nUna extensión maliciosa puede leer cualquier credencial de inicio guardada o ejecutar código arbitrario. \n \nAl confiar en este certificado aceptas estos riesgos. Extensión no confiable @@ -215,7 +215,7 @@ No se pudo descargar el capítulo debido a un error inesperado Error Descargador - Se requiere WebView para Tachiyomi + Se requiere WebView para que la aplicación funcione Fallo al evitar Cloudflare Actualización de extensión disponible @@ -523,7 +523,7 @@ Descarga automática Horizontal En vertical - Tipo de rotación + Rotación Derecha Izquierda Crea carpetas según el título del manga @@ -574,8 +574,8 @@ Algunos fabricantes tienen restricciones adicionales que cierran de forma forzada los servicios en segundo plano. Este sitio web tiene más información sobre cómo arreglarlo. Actividad en segundo plano Rastrear - Servicios que proveen funciones mejoradas para ciertas fuentes. Se hace un seguimiento automático del manga al añadirlo a la biblioteca. - Servicios mejorados + Ofrece funciones mejoradas para ciertas fuentes. Se hace un seguimiento automático del manga al añadirlo a la biblioteca. + Rastreadores mejorados Guia de rastreo Categorías excluidas Más alto @@ -598,7 +598,7 @@ Hoy Modo oscuro con negro puro - Tema Yotsuba + Yotsuba Yin y Yang Turquesa Tako @@ -830,6 +830,10 @@ Sincronizando biblioteca Se completó la sincronización de la biblioteca Toque aquí para obtener ayuda con Cloudflare - Inicio de sesión para seguimiento + Inicio de sesión del rastreador No se pudo acceder a %s + Desbloquear %s + Mover series al final + Marcas de tiempo relativas + \"%1$s\" en lugar de \"%2$s\" \ No newline at end of file diff --git a/i18n/src/main/res/values-ca/strings.xml b/i18n/src/main/res/values-ca/strings.xml index 633d812c7..898f7c2c5 100644 --- a/i18n/src/main/res/values-ca/strings.xml +++ b/i18n/src/main/res/values-ca/strings.xml @@ -818,4 +818,6 @@ HTTP %d, comproveu el lloc web en una WebView No s’ha pogut accedir a %s Mou la sèrie a baix de tot + Marques de temps relatives + «%1$s» en comptes de «%2$s» \ No newline at end of file diff --git a/i18n/src/main/res/values-cs/strings.xml b/i18n/src/main/res/values-cs/strings.xml index c9aee2595..a1ba82993 100644 --- a/i18n/src/main/res/values-cs/strings.xml +++ b/i18n/src/main/res/values-cs/strings.xml @@ -204,7 +204,7 @@ Bez animace Normální Rychle - Služby + Sledovače Vytvořit zálohu Obnovit zálohu Místo zálohy @@ -392,7 +392,7 @@ Chybějící zdroje: Záloha neobsahuje žádné položky knihovny. Neplatný soubor se zálohou - Jednosměrná synchronizace pro aktualizaci počtu přečtených kapitol ve sledovacích službách. Nastavení sledování pro každou položku je možné z jejich tlačítka sledování. + Jednosměrná synchronizace pro aktualizaci počtu přečtených kapitol v externích sledovacích službách. Nastavení sledování pro každou položku je možné z jejich tlačítka sledování. Povolení mazání kapitol se záložkami Smazat kapitoly Režim čtení @@ -572,8 +572,8 @@ Aktualizuji knihovnu… (%1$d / %2$d) Někteří výrobci používají další omezení aplikací, která vypíná služby na pozadí. Na této webové stránce najdete další informace o tom, jak to opravit. Pokud je MIUI optimalizace vypnutá, zálohování/obnovování nemusí fungovat správně. - Služby, které poskytují rozšířené funkce pro konkrétní zdroje. Záznamy jsou po přidání do knihovny automaticky sledovány. - Rozšířené služby + Poskytují rozšířené funkce pro konkrétní zdroje. Záznamy jsou po přidání do knihovny automaticky sledovány. + Vylepšené sledovače Návod ke sledování Čistě černý tmavý režim Jotsuba @@ -824,7 +824,7 @@ Má výsledky Synchronizace knihovny Synchronizace knihovny dokončena - Sledování přihlášení + Přihlášení sledovače Klepněte zde pro pomoc s Cloudflare Index stažených zneplatněn Nelze vytvořit soubor zálohy @@ -834,4 +834,6 @@ HTTP %d, zkontrolovat web v WebView Odemknout %s Přesunout sérii na konec + Relativní časová razítka + \"%1$s\" namísto \"%2$s\" \ No newline at end of file diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml index 052b79f3f..b0fa3de59 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -129,7 +129,7 @@ Ab viertletzt gelesenem Kapitel Ab fünftletzt gelesenem Kapitel Neue Kapitel herunterladen - Anbieter + Tracker Datensicherung erstellen Kann benutzt werden, um die aktuelle Bibliothek wiederherzustellen Datensicherung wiederherstellen @@ -409,7 +409,7 @@ Erledigt in %1$s mit %2$s Fehler Erledigt in %1$s mit %2$s Fehlern - Einweg-Synchronisation zum Aktualisieren der Kapitelfortschritte in den Trackingdiensten. Richte Tracking für einzelne Einträge über deren jeweiligen Tracking-Button ein. + Einweg-Synchronisation zum Aktualisieren der Kapitelfortschritte in den externen Trackingdiensten. Richte Tracking für einzelne Einträge über deren jeweiligen Trackingbutton ein. Bibliothekscover aktualisieren Diese Erweiterung stammt nicht aus der offiziellen Liste. Inoffiziell @@ -448,7 +448,7 @@ Auf v%1$s aktualisiert Was ist neu Herunterladen von Kapiteln aufgrund von zu wenig Speicherplatz nicht möglich - Nach „%1$s“ überall suchen + Überall nach „%1$s“ suchen Hinzufügedatum Lesemodus Thema @@ -572,8 +572,8 @@ Mitternachtsdämmerung Grüner Apfel App-Design - Erweiterte Anbieter - Anbieter, die für bestimmte Quellen erweiterte Funktionen anbieten. Einträge werden automatisch getrackt, wenn sie deiner Bibliothek hinzugefügt werden. + Erweiterte Tracker + Bieten für bestimmte Quellen erweiterte Funktionen an. Einträge werden automatisch getrackt, wenn sie deiner Bibliothek hinzugefügt werden. Dynamisch Hintergrundaktivität Niedrigste @@ -810,7 +810,7 @@ Bibliothekssynchronisierung abgeschlossen Tippe hier, um Hilfe zu Cloudflare zu erhalten Index der Downloads invalide - Tracking-Login + Tracker-Login Sicherungsdatei konnte nicht erstellt werden Lizenziert - Keine Kapitel zu zeigen HTTP %d, überprüfe die Webseite in WebView @@ -818,4 +818,6 @@ %s konnte nicht erreicht werden %s entsperren Serie nach unten verschieben + Relative Zeitstempel + „%1$s“ anstelle von „%2$s“ \ No newline at end of file diff --git a/i18n/src/main/res/values-el/strings.xml b/i18n/src/main/res/values-el/strings.xml index 6239e9d66..7439914a0 100644 --- a/i18n/src/main/res/values-el/strings.xml +++ b/i18n/src/main/res/values-el/strings.xml @@ -156,7 +156,7 @@ Προ-προ-προτελευταίο αναγνωσμένο κεφάλαιο Προ-προ-προ-προτελευταίο αναγνωσμένο κεφάλαιο Λήψη νέων κεφαλαίων - Υπηρεσίες + Ιχνηλάτες Δημιουργία αντιγράφου ασφαλείας Μπορεί να χρησιμοποιηθεί για επαναφορά τρέχουσας βιβλιοθήκης Επαναφορά αντιγράφου ασφαλείας @@ -409,7 +409,7 @@ Έγινε σε %1$s με %2$s σφάλμα Έγινε σε %1$s με %2$s σφάλματα - Μονόδρομος συγχρονισμός για ενημέρωση των υπηρεσιών παρακολούθησης προόδου κεφαλαίων. Ρυθμίστε την παρακολούθηση για μεμονωμένες καταχωρήσεις από το κουμπί παρακολούθησης τους. + Μονόδρομος συγχρονισμός για ενημέρωση των υπηρεσιών εξωτερικής παρακολούθησης προόδου κεφαλαίων. Ρυθμίστε την παρακολούθηση για μεμονωμένες καταχωρήσεις από το κουμπί παρακολούθησης τους. Ανανέωση εξώφυλλων βιβλιοθήκης Αυτή η επέκταση δεν προέρχεται από την επίσημη λίστα. Ανεπίσημη @@ -572,8 +572,8 @@ Γιν και Γιανγκ Tako Φράουλα Daiquiri - Υπηρεσίες που παρέχουν βελτιωμένες δυνατότητες για συγκεκριμένες πηγές. Οι καταχωρήσεις παρακολουθούνται αυτόματα όταν προστίθενται στη βιβλιοθήκη σας. - Βελτιωμένες υπηρεσίες + Παρέχει βελτιωμένες δυνατότητες για συγκεκριμένες πηγές. Οι καταχωρήσεις παρακολουθούνται αυτόματα όταν προστίθενται στη βιβλιοθήκη σας. + Ενισχυμένοι trackers Δυναμικό Δραστηριότητα παρασκηνίου Χαμηλότερη @@ -818,4 +818,6 @@ Δεν υπάρχει σύνδεση στο διαδίκτυο Ξεκλείδωμα %s Μετακίνηση σειράς προς τα κάτω + Σχετικές χρονικές σημάνσεις + \"%1$s\" αντί του \"%2$s\" \ No newline at end of file diff --git a/i18n/src/main/res/values-es/strings.xml b/i18n/src/main/res/values-es/strings.xml index eda92c287..0f8cd0446 100644 --- a/i18n/src/main/res/values-es/strings.xml +++ b/i18n/src/main/res/values-es/strings.xml @@ -101,7 +101,7 @@ Ubicación personalizada - Servicios + Servicios de seguimiento Vaciar la caché de capítulos Usado: %1$s @@ -608,8 +608,8 @@ El formato del capítulo no es correcto No se ha encontrado el capítulo Desactivar el modo incógnito - Servicios que ofrecen funciones mejoradas para ciertas fuentes. Se hace un seguimiento automático de los elementos al añadirlos a la biblioteca. - Servicios mejorados + Ofrece funciones mejoradas para ciertas fuentes. Se hace un seguimiento automático de los elementos al añadirlos a la biblioteca. + Servicios de seguimiento mejorados Guía de seguimiento Automático No @@ -857,7 +857,7 @@ Sincronizando la biblioteca Toca aquí para solucionar problemas de acceso con Cloudflare Se ha borrado el índice de descargas - Inicio de sesión de seguimiento + Iniciar sesión en el servicio No se ha podido crear un archivo de respaldo Con licencia oficial, sin capítulos que mostrar No se ha podido acceder a %s @@ -865,4 +865,6 @@ Sin conexión a Internet Desbloquear %s Mover al último puesto + Marcas de tiempo relativas + «%1$s» en vez de «%2$s» \ No newline at end of file diff --git a/i18n/src/main/res/values-fil/strings.xml b/i18n/src/main/res/values-fil/strings.xml index 475067172..bc086ddf6 100644 --- a/i18n/src/main/res/values-fil/strings.xml +++ b/i18n/src/main/res/values-fil/strings.xml @@ -818,4 +818,6 @@ HTTP %d, tignan ang website sa WebView Hindi maabot ang %s Ilagay sa ibaba ang serye + Mga relatibong timestamp + \"%1$s\" sa halip na \"%2$s\" \ No newline at end of file diff --git a/i18n/src/main/res/values-hr/strings.xml b/i18n/src/main/res/values-hr/strings.xml index e60b033c4..d7416aafe 100644 --- a/i18n/src/main/res/values-hr/strings.xml +++ b/i18n/src/main/res/values-hr/strings.xml @@ -166,7 +166,7 @@ Obnovi sigurnosnu kopiju Može se koristiti za obnavljanje trenutačne biblioteke Stvori sigurnosnu kopiju - Usluge + Usluge praćenja Ažuriraj napredak nakon čitanja Preuzmi nova poglavlja Peto prije zadnjeg pročitanog poglavlja @@ -423,7 +423,7 @@ Nedostaju izvori: Sigurnosna kopija ne sadrži unose u biblioteci. Neispravna datoteka sigurnosne kopije - Jednosmjerna sinkronizacija za aktualiziranje napretka poglavlja u usluzi praćenja. Postavi praćenje pojedinačnih unosa manga putem gumba za praćenje. + Jednosmjerna sinkronizacija za aktualiziranje napretka poglavlja u eksternoj usluzi praćenja. Postavi praćenje pojedinačnih unosa manga putem gumba za praćenje. Ovo proširenje nije iz službenog popisa. Neslužbeno Provjeri nove naslovnice i pojedinosti prilikom aktualiziranja biblioteke @@ -462,9 +462,9 @@ Tema Datum dodavanja - %d praćenje - %d praćenja - %d praćenja + %d usluga praćenja + %d usluge praćenja + %d usluga praćenja Nemaš označenih izvora Gotovo @@ -474,7 +474,7 @@ Izbriši poglavlja Izvori ovog proširenja mogu sadržavati neprikladan sadržaj (18+) 18+ - Praćenja bez prijave: + Usluge praćenja bez prijave: To ne sprečava neslužbene ili potencijalno krivo označena proširenja prikazati neprikladan sadržaj (18+) unutar aplikacije. Preskače se %d poglavlje. Ne postoji u izvoru ili je filtrirano @@ -568,8 +568,8 @@ Isključeno Uključeno Postavke kategorija za sortiranje - Aktualiziraj pratioce prilikom aktualiziranja biblioteke - Automatski osvježi pratioce + Aktualiziraj usluge praćenja prilikom aktualiziranja biblioteke + Automatski aktualiziraj usluge praćenja Ograničenja: %s Pokreni preuzimanje sada Neki proizvođači imaju dodatna programska ograničenja koja onemogućuju pozadinske usluge. Ova web-stranica sadrži daljnje informacije o tome kako to popraviti. @@ -621,8 +621,8 @@ Ažuriranja aplikacije Nema se što raščistiti S nepročitanim poglavljima - Poboljšane usluge - Usluge koje pružaju poboljšane značajke za određene izvore. Unosi se automatski prate kada se dodaju u biblioteku. + Poboljšane usluge praćenja + Pruža poboljšane značajke za određene izvore. Unosi se automatski prate kada se dodaju u biblioteku. Prati Politika privatnosti Preskoči ažuriranje unosa @@ -720,7 +720,7 @@ Nema opisa Unosi Globalno aktualiziranje - Pratitelji + Usluge praćenja Srednja ocjena Korišteno %dd @@ -823,7 +823,7 @@ Sinkroniziranje biblioteke završeno Dodirni ovdje za pomoć s Cloudflareom Ispušteno\? Zadnjih 20 dana i 2 mjeseca - Zapis praćenja + Prijava za uslugu praćenja Prekoraöeno razdoblje provjere Provjera zadnjih 10 i više dana Indeks preuzimanja poništen @@ -834,4 +834,6 @@ HTTP %d, provjeri web stranicu u WebView Nije bilo moguće povezati se s računalom %s Pomakni seriju na kraj + Relativne vremenske oznake + „%1$s” umjesto „%2$s” \ No newline at end of file diff --git a/i18n/src/main/res/values-in/strings.xml b/i18n/src/main/res/values-in/strings.xml index 1f4824c66..cff2bb024 100644 --- a/i18n/src/main/res/values-in/strings.xml +++ b/i18n/src/main/res/values-in/strings.xml @@ -110,7 +110,7 @@ Kiri Kanan Tengah - Tipe rotasi bawaan + rotasi bawaan Bebas Terkunci tegak Terkunci mendatar @@ -129,7 +129,7 @@ Bab keempat dari terakhir dibaca Bab kelima dari terakhir dibaca Unduh bab baru - Layanan + Pelacakan Buat cadangan Dapat digunakan untuk memulihkan isi pustaka saat ini Pulihkan cadangan @@ -400,7 +400,7 @@ Selesai dalam %1$s dengan %2$s kesalahan - Sinkronisasi satu arah untuk memperbarui kemajuan bab dalam layanan pelacakan. Siapkan pelacakan untuk entri individu dari tombol pelacakan mereka. + Sinkronisasi satu arah untuk memperbarui kemajuan bab di layanan pelacak eksternal. Siapkan pelacakan untuk setiap entri dari tombol pelacaknya. Ekstensi ini bukan dari daftar resmi. Tidak resmi Periksa sampul dan detail baru saat memperbarui pustaka @@ -523,7 +523,7 @@ Layar mendatar Layar Tegak Entri dalam kategori yang dikecualikan tidak akan diunduh meskipun mereka juga termasuk dalam kategori yang disertakan. - Jenis rotasi + Rotasi Skala abu-abu Tampilkan zona ketukan Entri dalam kategori yang dikecualikan tidak akan diperbarui meskipun mereka juga termasuk dalam kategori yang disertakan. @@ -551,8 +551,8 @@ Beberapa pabrikan mempunyai batasan aplikasi tambahan yang mematikan layanan latar belakang. Website ini memiliki info lebih lanjut untuk memperbaikinya. Memperbarui pustaka... (%1$d/%2$d) Pencadangan/pemulihan mungkin tidak berfungsi jika Optimisasi MIUI dimatikan. - Layanan yang menyediakan fitur yang ditingkatan untuk sumber tertentu. Entri dilacak secara otomatis ketika ditambahkan ke pustaka Anda. - Layanan yang ditingkatkan + Menyediakan fitur yang disempurnakan untuk sumber tertentu. Entri secara otomatis dilacak ketika ditambahkan ke perpustakaan Anda. + Pelacak yang ditingkatkan Mode gelap hitam pekat yotsuba Yin dan Yang @@ -801,4 +801,7 @@ Tidak ada koneksi Internet HTTP %d, periksa situs web di WebView Tidak dapat mencapai %s + Pindahkan seri ke bawah + Penanda waktu + \"%1$s\" seharusnya \"%2$s\" \ No newline at end of file diff --git a/i18n/src/main/res/values-it/strings.xml b/i18n/src/main/res/values-it/strings.xml index a6c7c1b04..c4151930e 100644 --- a/i18n/src/main/res/values-it/strings.xml +++ b/i18n/src/main/res/values-it/strings.xml @@ -122,7 +122,7 @@ Quintultimo capitolo letto Scarica nuovi capitoli - Servizi + Servizi di tracking Cancella cache capitoli Usati: %1$s @@ -444,7 +444,7 @@ Completato in %1$s con %2$s errori %02d min, %02d sec - Sincronizzazione a senso unico per aggiornare l\'avanzamento del capitolo sui servizi di tracking. Imposta il tracking per le singole voci dai loro pulsanti di tracking. + Sincronizzazione a senso unico per aggiornare l\'avanzamento dei capitoli sui servizi di tracking. Imposta il tracking per le singole voci dai loro pulsanti di tracking. Riduce il banding, ma potrebbe influire sulle prestazioni %d categoria @@ -633,8 +633,8 @@ Predefinita Attività in secondo piano Le funzioni di backup e ripristino potrebbero non funzionare correttamente se le ottimizzazioni MIUI sono disabilitate. - Servizi che offrono funzioni migliorate per fonti specifiche. Le voci sono tracciate automaticamente quando aggiunte alla libreria. - Servizi migliorati + Offrono funzioni migliorate per fonti specifiche. Le voci sono tracciate automaticamente quando aggiunte alla libreria. + Servizi di tracking migliorati Aspetto Traccia Guida introduttiva @@ -859,7 +859,7 @@ Sincronizzazione libreria Tocca qua per assistenza con Cloudflare Indice dei download invalidato - Login del tracking + Login del trakcer Non è stato possibile creare un file di backup Licenziato - Nessun capitolo da mostrare HTTP %d, controlla il sito nella WebView @@ -867,4 +867,6 @@ %s non raggiungibile Sblocca %s Spostare la serie in fondo + Timestamp relativi + «%1$s» invece di «%2$s» \ No newline at end of file diff --git a/i18n/src/main/res/values-ja/strings.xml b/i18n/src/main/res/values-ja/strings.xml index 35138b26f..9dfee3f0d 100644 --- a/i18n/src/main/res/values-ja/strings.xml +++ b/i18n/src/main/res/values-ja/strings.xml @@ -35,7 +35,7 @@ 既読にする 未読にする 削除する - ライブラリを更新する + ライブラリを更新 編集 カテゴリを追加 カテゴリを編集 @@ -177,7 +177,7 @@ 最後に読んだ章の3番目 最後に読んだ章の4番目 最後に読んだ章の5番目 - サービス + トラッカー 復元が完了しました バックアップしたいのは? バックアップを復元中 @@ -352,7 +352,7 @@ ソースがありません: バックアップにはライブラリの項目が含まれません。 バックアップファイルは無効です - 一方同期の追跡サービスにある章の読書進捗を更新します。個別の項目の「同期」ボタンで追跡サービスを設定してください。 + 一方同期の外部追跡サービスにある章の読書進捗を更新します。個別の項目の「同期」ボタンで追跡サービスを設定してください。 余白 読書中 章の間の遷移ページを常に表示 @@ -589,8 +589,8 @@ Shizukuは実行中ではありません 項目数 拡張機能をインストール中… - 高度なサービス - 特定ソース専用の高度な機能を提供するサービスです。項目はライブラリに追加される時、自動で追跡され始めます。 + 高度な追跡サービス + 特定ソース専用の高度な機能を提供します。項目はライブラリに追加される時、自動で追跡され始めます。 ほかの場所にもバックアップのコピーを保管してください。 システムログにverboseログを出力(アプリのパフォーマンスが低下します) 大規模のアップデートはソースに有害で、ソースを遅くし、電池の消耗を増加する可能性があります。詳しくはタップでご覧ください。 @@ -795,11 +795,13 @@ Cloudflareに関するヘルプ情報はこちら ダウンロード インデックスを消去しました バックアップ ファイルを作成できませんでした - トラッキング サービスにログイン + 追跡サービスにログイン ライセンス制限あり—章を表示できません HTTP %d、WebViewでこのWebサイトを確認してください インターネット接続がありません %sにアクセスできませんでした %sをアンロック シリーズを底に移動 + 相対的なタイムスタンプ + 「%2$s」の代わりに「%1$s」を使用 \ No newline at end of file diff --git a/i18n/src/main/res/values-pl/strings.xml b/i18n/src/main/res/values-pl/strings.xml index e208a925c..dd1ec001c 100644 --- a/i18n/src/main/res/values-pl/strings.xml +++ b/i18n/src/main/res/values-pl/strings.xml @@ -305,7 +305,7 @@ Wylogowano Wstrzymane Zawsze pokazuj przejścia rozdziałów - Pionowo bez przerw + Pionowo z przerwami Pomijaj odfiltrowane rozdziały Wyświetlanie Ukryj zawartość powiadomienia diff --git a/i18n/src/main/res/values-pt-rBR/strings.xml b/i18n/src/main/res/values-pt-rBR/strings.xml index 505208425..0d0b9538b 100644 --- a/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/i18n/src/main/res/values-pt-rBR/strings.xml @@ -131,7 +131,7 @@ Quarto capítulo lido antes do último Quinto capítulo lido antes do último Fazer download de novos capítulos - Serviços + Monitoradores Criar backup Pode ser usado para restaurar a biblioteca atual Restaurar backup @@ -417,7 +417,7 @@ Concluído em %1$s com %2$s erros Concluído em %1$s com %2$s erros - Sincronização unidirecional para atualizar o progresso dos capítulos nos serviços de monitoramento. Configure o monitoramento para itens individuais a partir de seus botões de monitoramento. + Sincronização unidirecional para atualizar o progresso dos capítulos nos serviços monitoradores externos. Configure o monitoramento para itens individuais a partir de seus botões de monitoramento. Atualizar as capas da biblioteca Esta extensão não é da lista oficial. Não oficial @@ -583,8 +583,8 @@ Aurora-da-noite Maçã-verde Tema do aplicativo - Serviços que oferecem recursos aprimorados para fontes específicas. Os itens são automaticamente monitorados quando adicionados em sua biblioteca. - Serviços aprimorados + Oferecem recursos aprimorados para fontes específicas. Os itens são automaticamente monitorados quando adicionados em sua biblioteca. + Monitoradores aprimorados Dinâmico Atividade em segundo plano Mais baixa @@ -826,7 +826,7 @@ Sincronização da biblioteca finalizada Toque aqui para obter ajuda com o Cloudflare Índice de downloads invalidado - Login do monitoramento + Login do monitorador Não foi possível criar o arquivo do backup Licenciado - Nenhum capítulo para mostrar HTTP %d, verifique o site na WebView @@ -834,4 +834,6 @@ Não foi possível resolver %s Desbloquear o %s Mover série para o final + Datas relativas + \"%1$s\" ao invés de \"%2$s\" \ No newline at end of file diff --git a/i18n/src/main/res/values-ru/strings.xml b/i18n/src/main/res/values-ru/strings.xml index 9b9a8e47a..94ac19fe7 100644 --- a/i18n/src/main/res/values-ru/strings.xml +++ b/i18n/src/main/res/values-ru/strings.xml @@ -160,7 +160,7 @@ Растянуть Оценка Предпоследняя прочитанная глава - Сервисы + Сервисы отслеживания Установить как обложку Номер главы Название источника @@ -426,7 +426,7 @@ Выполнено за %1$s с %2$s ошибками Выполнено за %1$s с %2$s ошибками - Односторонняя синхронизация для обновления прогресса в сервисах отслеживания. Настройте отслеживание при помощи кнопки «Отслеживание». + Односторонняя синхронизация для обновления прогресса в сторонних сервисах отслеживания. Настройте отслеживание при помощи кнопки «Отслеживание». Это расширение не входит в официальный список расширений. Неофициальное Дата добавления @@ -594,8 +594,8 @@ Обновление библиотеки… (%1$d/%2$d) У некоторых производителей есть дополнительные ограничения для приложений, которые убивают фоновые службы. На этом сайте есть более подробная информация о том, как это исправить. Резервная копия/Восстановление может не работать должным образом, если отключена «Оптимизация MIUI». - Сервисы, предоставляющие расширенные возможности для определённых источников. Серии будут автоматически отслеживаться при добавлении в библиотеку. - Расширенные сервисы + Предоставляет расширенные возможности для определённых источников. Серии будут автоматически отслеживаться при добавлении в библиотеку. + Расширенные сервисы отслеживания Динамическая Фоновая активность Самая низкая @@ -850,4 +850,6 @@ Не удалось достичь %s Разблокировать %s Переместить серию в конец + Относительные временные метки + \"%1$s\" вместо \"%2$s\" \ No newline at end of file diff --git a/i18n/src/main/res/values-sc/strings.xml b/i18n/src/main/res/values-sc/strings.xml index 8d4b42c45..8f8040bcc 100644 --- a/i18n/src/main/res/values-sc/strings.xml +++ b/i18n/src/main/res/values-sc/strings.xml @@ -99,9 +99,9 @@ Estensione non afidàbile Custa estensione est istada firmada cun unu tzertificadu chi no est afidàbile e no est istada ativada. \n -\nUn\'estensione mala diat pòdere lèghere totu sas informatziones de atzessu sarvadas in Tachiyomi o fàghere eseguire còdighe arbitràriu. +\nUn\'estensione mala diat pòdere lèghere totu sas informatziones de atzessu sarvadas o fàghere esecutare còdighe arbitràriu. \n -\nPonende fidùtzia in custu tzertificadu atzetas custos arriscos. +\nPonende fide in custu tzertificadu atzetas custos arriscos. Ischermu intreu Ànima sas transitziones de sas pàginas Lestresa de s\'animatzione de su tocu dòpiu @@ -113,7 +113,7 @@ Navigatzione Teclas de su volume Fùrria sas teclas de su volume - Ammustra cun su tocu longu + Ammustra sas atziones cun su tocu longu Colore de isfundu Arbu/biancu Nieddu @@ -138,7 +138,7 @@ Peruna animatzione Normale Lestra - Casta predefinida de rotatzione + Rotatzione predefinida Lìbera Blocadu in verticale Blocadu in orizontale @@ -157,7 +157,7 @@ Cuartùrtimu capìtulu lèghidu Cuintùrtimu capìtulu lèghidu Iscàrriga sos capìtulos noos - Servìtzios + Arrastadores Crea una còpia de seguresa Podet èssere impreada pro ripristinare sa biblioteca atuale Riprìstina una còpia de seguresa @@ -377,7 +377,7 @@ Annanghe a sa biblioteca De mancu De prus - Pro Tachiyomi b\'at bisòngiu de WebView + Pro chi s\'aplicatzione funtzionet b\'at bisòngiu de WebView Litzèntzias a còdighe abertu Situ web Iscarrigados ebbia @@ -409,9 +409,9 @@ Fatu in %1$s cun %2$s errore Fatu in %1$s cun %2$s errores - Sincronizatzione a una diretzione ebbia pro agiornare su progressu in sos capìtulos in su servìtziu de arrastamentu. Imposta s\'arrastamentu pro sos elementos dae su butone de arrastamentu issoro. + Sincronizatzione a una diretzione ebbia pro agiornare su progressu in sos capìtulos in servìtzios de arrastamentu esternos. Imposta s\'arrastamentu pro sos elementos dae su butone de arrastamentu issoro. Annoa sas coberteddas de sa biblioteca - Custa estensione non benit dae sa lista de estensiones ufitziales de Tachiyomi. + Custa estensione non benit dae sa lista ufitziale. No ufitziale Pro data de carrigamentu Datos @@ -532,7 +532,7 @@ Custa versione de Android no est prus suportada Orizontale Verticale - Casta de rotatzione + Rotatzione Creat cartellas in base a su tìtulu de sos elementos Sarva sas pàginas in cartellas separadas Atziones @@ -564,8 +564,8 @@ Tako Agiornende sa biblioteca… (%1$d/%2$d) Sa còpia de seguresa e su riprìstinu diant pòdere non funtzionare comente si tocat si s\'otimizatzione MIUI est disabilitada. - Servìtzios chi frunint funtzionalidades avantzadas pro fontes ispetzìficas. Sos elementos benint arrastados in manera automàtica cando los annanghes a sa biblioteca tua. - Servìtzios avantzados + Frunit funtzionalidades avantzadas pro fontes ispetzìficas. Sos elementos benint arrastados in manera automàtica cando los annanghes a sa biblioteca tua. + Arrastadores avantzados Modalidade iscura niedda pura Yotsuba Yin e Yang @@ -805,4 +805,19 @@ %d dies Iscantzella sos iscarrigados + Toca inoghe pro agiudu cun Cloudflare + Isbloca %s + Sincronizende sa biblioteca + Non at s\'est pòdidu creare un\'archìviu de còpia de seguresa + Sincronizatzione de sa biblioteca acabada + Moe sa sèrie a fundu + Cun lissèntzia ufitziale - Perunu capìtulu de ammustrare + Peruna connessione a ìnternet + Ìnditze de sos iscarrigamentos invalidadu + Tenet resurtados + Atzessu a s\'arrastadore + Marcas temporales relativas + HTTP %d, verìfica su situ in WebView + \"%1$s\" in càmbiu de \"%2$s\" + Non s\'est pòdidu atzèdere a %s \ No newline at end of file diff --git a/i18n/src/main/res/values-sk/strings.xml b/i18n/src/main/res/values-sk/strings.xml index 699246092..a71d1433c 100644 --- a/i18n/src/main/res/values-sk/strings.xml +++ b/i18n/src/main/res/values-sk/strings.xml @@ -480,7 +480,7 @@ Zoznam pozastavených položiek Stiahnuť dopredu Automatické sťahovanie počas čítania - Funguje iba na položkách v knižnici a ak je aktuálna kapitola a nasledujúca kapitola už stiahnutá + Funguje iba na položkách v knižnici a ak je aktuálna kapitola a nasledujúca kapitola už stiahnutá. Neznámy stav Prestávka Pridať sledovanie @@ -574,7 +574,7 @@ Inštaluje sa rozšírenie… Invertovať oblasti dotyku Uloženie stránok do samostatných priečinkov - Sivá + Šedivá Na šírku Obnovenie už prebieha Uložiť logy o chybách do súboru na zdieľanie s vývojármi @@ -658,7 +658,7 @@ Preskočenie %d kapitoly, buď zdroj chýba, alebo bol odfiltrovaný Preskočenie %d kapitol, buď zdroj chýba, alebo bol odfiltrovaný - Preskočenie %d kapitol, buď zdroj chýba, alebo bol odfiltrovaný + Zložky %d kapitoly, buď zdroj chýba, alebo boli filtrované Chyba pri ukladaní obrázka Aktualizácie aplikácie diff --git a/i18n/src/main/res/values-th/strings.xml b/i18n/src/main/res/values-th/strings.xml index 7554082bf..a33e46839 100644 --- a/i18n/src/main/res/values-th/strings.xml +++ b/i18n/src/main/res/values-th/strings.xml @@ -157,7 +157,7 @@ ตอนที่สี่ก่อนตอนที่อ่านล่าสุด ตอนที่ห้าก่อนตอนที่อ่านล่าสุด ดาวน์โหลดตอนใหม่ - บริการ + ตัวติดตาม สำรองข้อมูล สามารถใช้ในการเรียกคืนค่าคลังปัจจุบัน เรียกคืนค่าการสำรองข้อมูล @@ -496,7 +496,7 @@ แหล่งที่มาที่หายไป: แฟ้มสํารองข้อมูลไม่มีรายการคลังใด ๆ ข้อมูลสำรองไม่ถูกต้อง - ซิงค์ทางเดียวเพื่ออัปเดตความคืบหน้าของตอนกับบริการการติดตาม ตั้งค่าการติดตามรายการในแต่ละรายการได้จากปุ่มติดตาม + ซิงค์ทางเดียวเพื่ออัปเดตความคืบหน้าของตอนกับตัวติดตามภายนอก ตั้งค่าการติดตามรายการในแต่ละรายการได้จากปุ่มติดตาม รายการในหมวดหมู่ที่ยกเว้นไว้จะไม่ถูกดาวน์โหลดแม้ว่าจะอยู่ในหมวดหมู่ที่รวมอยู่ด้วยก็ตาม ดาวน์โหลดอัตโนมัติ กำลังตรวจสอบตอนหาใหม่ @@ -566,7 +566,7 @@ %1$d วันที่ผ่านมา - บริการขั้นสูง + ตัวติดตามขั้นสูง ควรเก็บสำเนาของข้อมูลสำรองไว้ที่อื่นด้วยเช่นกัน บันทึกบันทึกอย่างละเอียดไปยังบันทึกของระบบ (ลดประสิทธิภาพของแอป) ช่วยแปล @@ -591,8 +591,8 @@ เร็วที่สุด เร็ว คู่มือการติดตาม - หมวดหมู่ที่ยกเว้น - บริการที่มีคุณลักษณะขั้นสูงสำหรับแหล่งที่มาเฉพาะ รายการจะถูกติดตามโดยอัตโนมัติเมื่อเพิ่มลงในคลัง + หมวดหมู่ที่ยกเว้นไว้ + ใช้สำหรับเฉพาะบางแหล่งที่มา รายการจะถูกติดตามโดยอัตโนมัติเมื่อเพิ่มลงในคลัง ข้อมูลแอพ เกิดข้อผิดพลาดในการรับรายการส่วนขยาย ล้างแคชตอนในเมื่อเปิดแอพ @@ -796,10 +796,12 @@ แตะที่นี่เพื่อขอความช่วยเหลือเกี่ยวกับ Cloudflare ไม่สามารถสร้างไฟล์สำรองข้อมูล มีลิขสิทธิ์แล้ว - ไม่มีตอนให้แสดง - เข้าสู่ระบบการติดตาม + เข้าสู่ระบบตัวติดตาม ปลดล็อก %s ไม่มีการเชื่อมต่ออินเทอร์เน็ต HTTP %d, ดูเว็บไซต์ใน WebView ไม่สามารถเข้าถึง %s ได้ ย้ายเรื่องไปด้านล่าง + ประทับเวลาแบบสัมพันธ์กัน + แสดง \"%1$s\" แทน \"%2$s\" \ No newline at end of file diff --git a/i18n/src/main/res/values-uk/strings.xml b/i18n/src/main/res/values-uk/strings.xml index e2241a1f7..863ca3c0c 100644 --- a/i18n/src/main/res/values-uk/strings.xml +++ b/i18n/src/main/res/values-uk/strings.xml @@ -156,7 +156,7 @@ Четвертий від останнього прочитаного розділу П\'ятий від останнього прочитаного розділу Завантажувати нові розділи - Сервіси + Трекери Створити резервну копію Можна використовувати для відновлення поточної бібліотеки Відновити резервну копію @@ -433,7 +433,7 @@ Відсутні джерела: Бекап не містить жодних записів бібліотеки. Невірний файл резервної копії - Одностороння синхронізація для оновлення прогресу розділу в службах стеження. Налаштуйте для окремих записів з допомогою кнопки \"Стежити\". + Одностороння синхронізація для оновлення прогресу розділу у зовнішніх сервісах стеження. Налаштуйте відстеження окремих записів за допомогою кнопки відстеження. Показувати вкладки категорій Зручна сітка Розд. %1$s - %2$s @@ -585,8 +585,8 @@ У деяких виробників є додаткові обмеження застосунків, котрі вбивають фонові сервіси. На цьому сайті більше інформації з приводу того, як це виправити. Фонова активність Резервування/Відновлення можуть не працювати належним чином, у випадку, якщо вимкнено Оптимізацію MIUI. - Сервіси, які надають розширені можливості для певних джерел. Записи будуть автоматично відстежуватись при додаванні до бібліотеки. - Розширені сервіси + Надає розширені функції для конкретних джерел. Записи автоматично відстежуються при додаванні до бібліотеки. + Розширені трекери Найнижча Низька Висока @@ -839,7 +839,7 @@ Має результати Синхронізацію бібліотеки завершено Синхронізація бібліотеки - Відстеження входу + Логін трекера Індекс завантажень недійсний Натисніть тут, щоб отримати допомогу з Cloudflare Не вдалося створити файл резервної копії @@ -849,4 +849,6 @@ Немає Інтернет-з\'єднання Http %d, перевірте вебсайт у WebView Не вдалося досягти %s + Відносні позначки часу + \"%1$s\" замість \"%2$s\" \ No newline at end of file diff --git a/i18n/src/main/res/values-zh-rTW/strings.xml b/i18n/src/main/res/values-zh-rTW/strings.xml index 71241a535..9fa76f271 100644 --- a/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/i18n/src/main/res/values-zh-rTW/strings.xml @@ -113,7 +113,7 @@ 自訂位置 已停用 自動下載新章節 - 服務 + 歷程平台 建立備份 還原備份 備份位置 @@ -398,7 +398,7 @@ 共 %1$s 章 - 將章節進度單向同步至閱讀歷程平台,請逕行前往個別作品的「歷程」專區以設置。 + 將閱讀進度單向同步至外部歷程平台。請逕行前往個別作品的「歷程」專區以設置。 %d 個類別 @@ -552,8 +552,8 @@ 部分裝置製造商設有額外的應用程式限制來終止背景服務。此網站提供了修復這項問題的詳細資訊。 背景活動 若停用 MIUI 最佳化,備份與還原可能無法正確執行。 - 為特定來源提供增強功能的服務。當作品被加入書櫃時,將自動登錄閱讀歷程。 - 增強服務 + 為特定來源提供增強功能。當作品被加入書櫃時,將自動登錄閱讀歷程。 + 增強式歷程平台 歷程平台說明 獨立各類別的排序方式 純黑深色模式 @@ -583,7 +583,7 @@ 入門指南 新增 協助翻譯 - 排除的類別 + 不包括的漫畫類別 程式資訊 若要使用 Shizuku 來安裝擴充套件,請先安裝 Shizuku 並開啟之。 傳統 @@ -801,5 +801,7 @@ 沒有網際網路連線 無法連上 %s 解鎖 %s - 將系列移至底部 + 置底此作品 + 相對時間戳記 + 以「%1$s」表示「%2$s」 \ No newline at end of file From e47f4cc177485b36cde7f97c54a35ca6540c62ec Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 7 Oct 2023 10:03:45 -0400 Subject: [PATCH 47/59] Specify broadcast receiver export flags Really only useful once we target Android 14, but doesn't hurt to do it now. --- .../tachiyomi/extension/installer/PackageInstallerInstaller.kt | 3 ++- .../eu/kanade/tachiyomi/extension/util/ExtensionInstaller.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/PackageInstallerInstaller.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/PackageInstallerInstaller.kt index 0b6b3e724..fc8d0f46c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/PackageInstallerInstaller.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/PackageInstallerInstaller.kt @@ -8,6 +8,7 @@ import android.content.Intent import android.content.IntentFilter import android.content.pm.PackageInstaller import android.os.Build +import androidx.core.content.ContextCompat import eu.kanade.tachiyomi.extension.model.InstallStep import eu.kanade.tachiyomi.util.lang.use import eu.kanade.tachiyomi.util.system.getParcelableExtraCompat @@ -100,7 +101,7 @@ class PackageInstallerInstaller(private val service: Service) : Installer(servic } init { - service.registerReceiver(packageActionReceiver, IntentFilter(INSTALL_ACTION)) + ContextCompat.registerReceiver(service, packageActionReceiver, IntentFilter(INSTALL_ACTION), ContextCompat.RECEIVER_EXPORTED) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstaller.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstaller.kt index 5ea3a3ee6..01f212d8e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstaller.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstaller.kt @@ -264,7 +264,7 @@ internal class ExtensionInstaller(private val context: Context) { isRegistered = true val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) - context.registerReceiver(this, filter) + ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_EXPORTED) } /** From c66a4fa7a72215a39fc783914c26f7db1de37a6e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Oct 2023 23:25:11 -0400 Subject: [PATCH 48/59] Update dependency androidx.benchmark:benchmark-macro-junit4 to v1.2.0-rc02 (#9990) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 5c6aca3f9..f9db071ec 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -27,7 +27,7 @@ guava = "com.google.guava:guava:32.1.2-android" paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging_version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } -benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-rc01" +benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-rc02" test-ext = "androidx.test.ext:junit-ktx:1.2.0-alpha01" test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-alpha01" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0-alpha04" From 9c688b08c0fd3b501dbf0e0f35b3b0fdb301052f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Oct 2023 23:29:14 -0400 Subject: [PATCH 49/59] Update dependency com.google.android.material:material to v1.10.0 (#9991) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1ee77f26b..2f37fce8b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -52,7 +52,7 @@ natural-comparator = "com.github.gpanther:java-nat-sort:natural-comparator-1.1" richtext-commonmark = { module = "com.halilibo.compose-richtext:richtext-commonmark", version.ref = "richtext" } richtext-m3 = { module = "com.halilibo.compose-richtext:richtext-ui-material3", version.ref = "richtext" } -material = "com.google.android.material:material:1.9.0" +material = "com.google.android.material:material:1.10.0" flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013533" photoview = "com.github.chrisbanes:PhotoView:2.3.0" directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" From 72024aa44af1622fd148b859c8cea0c3404dc370 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 8 Oct 2023 10:40:58 -0400 Subject: [PATCH 50/59] Add app settings to backups This should be compatible with Aniyomi's implementation. Related to #1857 Co-authored-by: jmir1 --- .../settings/screen/SettingsBackupScreen.kt | 1 + .../tachiyomi/data/backup/BackupConst.kt | 9 +++- .../tachiyomi/data/backup/BackupManager.kt | 37 +++++++++++-- .../tachiyomi/data/backup/BackupRestorer.kt | 53 ++++++++++++++++++- .../tachiyomi/data/backup/models/Backup.kt | 2 +- .../data/backup/models/BackupCategory.kt | 1 - .../data/backup/models/BackupPreference.kt | 31 +++++++++++ .../core/preference/AndroidPreference.kt | 9 +++- .../core/preference/AndroidPreferenceStore.kt | 4 ++ .../core/preference/PreferenceStore.kt | 2 + i18n/src/main/res/values/strings.xml | 1 + 11 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt index ad2a00380..a5adfb75d 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt @@ -147,6 +147,7 @@ object SettingsBackupScreen : SearchableSettings { BackupConst.BACKUP_CHAPTER to R.string.chapters, BackupConst.BACKUP_TRACK to R.string.track, BackupConst.BACKUP_HISTORY to R.string.history, + BackupConst.BACKUP_APP_PREFS to R.string.app_settings, ) } val flags = remember { choices.keys.toMutableStateList() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt index add7b3813..a137046e4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt @@ -4,11 +4,18 @@ package eu.kanade.tachiyomi.data.backup internal object BackupConst { const val BACKUP_CATEGORY = 0x1 const val BACKUP_CATEGORY_MASK = 0x1 + const val BACKUP_CHAPTER = 0x2 const val BACKUP_CHAPTER_MASK = 0x2 + const val BACKUP_HISTORY = 0x4 const val BACKUP_HISTORY_MASK = 0x4 + const val BACKUP_TRACK = 0x8 const val BACKUP_TRACK_MASK = 0x8 - const val BACKUP_ALL = 0xF + + const val BACKUP_APP_PREFS = 0x10 + const val BACKUP_APP_PREFS_MASK = 0x10 + + const val BACKUP_ALL = 0x1F } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index 67bb74e97..941878109 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt @@ -6,6 +6,8 @@ import android.net.Uri import com.hippo.unifile.UniFile import eu.kanade.domain.chapter.model.copyFrom import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_APP_PREFS +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_APP_PREFS_MASK import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER @@ -18,8 +20,15 @@ import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.backup.models.BackupCategory import eu.kanade.tachiyomi.data.backup.models.BackupHistory import eu.kanade.tachiyomi.data.backup.models.BackupManga +import eu.kanade.tachiyomi.data.backup.models.BackupPreference import eu.kanade.tachiyomi.data.backup.models.BackupSerializer import eu.kanade.tachiyomi.data.backup.models.BackupSource +import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.FloatPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.IntPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.LongPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue import eu.kanade.tachiyomi.data.backup.models.backupCategoryMapper import eu.kanade.tachiyomi.data.backup.models.backupChapterMapper import eu.kanade.tachiyomi.data.backup.models.backupTrackMapper @@ -30,6 +39,7 @@ import logcat.LogPriority import okio.buffer import okio.gzip import okio.sink +import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.util.system.logcat import tachiyomi.data.DatabaseHandler import tachiyomi.data.Manga_sync @@ -61,6 +71,7 @@ class BackupManager( private val getCategories: GetCategories = Injekt.get() private val getFavorites: GetFavorites = Injekt.get() private val getHistory: GetHistory = Injekt.get() + private val preferenceStore: PreferenceStore = Injekt.get() internal val parser = ProtoBuf @@ -81,6 +92,7 @@ class BackupManager( backupCategories(flags), emptyList(), prepExtensionInfoForSync(databaseManga), + backupAppPreferences(flags), ) var file: UniFile? = null @@ -133,7 +145,7 @@ class BackupManager( } } - fun prepExtensionInfoForSync(mangas: List): List { + private fun prepExtensionInfoForSync(mangas: List): List { return mangas .asSequence() .map(Manga::source) @@ -148,7 +160,7 @@ class BackupManager( * * @return list of [BackupCategory] to be backed up */ - suspend fun backupCategories(options: Int): List { + private suspend fun backupCategories(options: Int): List { // Check if user wants category information in backup return if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) { getCategories.await() @@ -159,7 +171,7 @@ class BackupManager( } } - suspend fun backupMangas(mangas: List, flags: Int): List { + private suspend fun backupMangas(mangas: List, flags: Int): List { return mangas.map { backupManga(it, flags) } @@ -219,6 +231,25 @@ class BackupManager( return mangaObject } + @Suppress("UNCHECKED_CAST") + private fun backupAppPreferences(flags: Int): List { + if (flags and BACKUP_APP_PREFS_MASK != BACKUP_APP_PREFS) return emptyList() + + return preferenceStore.getAll().mapNotNull { (key, value) -> + when (value) { + is Int -> BackupPreference(key, IntPreferenceValue(value)) + is Long -> BackupPreference(key, LongPreferenceValue(value)) + is Float -> BackupPreference(key, FloatPreferenceValue(value)) + is String -> BackupPreference(key, StringPreferenceValue(value)) + is Boolean -> BackupPreference(key, BooleanPreferenceValue(value)) + is Set<*> -> (value as? Set)?.let { + BackupPreference(key, StringSetPreferenceValue(it)) + } + else -> null + } + } + } + internal suspend fun restoreExistingManga(manga: Manga, dbManga: Mangas): Manga { var updatedManga = manga.copy(id = dbManga._id) updatedManga = updatedManga.copyFrom(dbManga) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt index 765a700c1..1c0558b4d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt @@ -7,13 +7,20 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.models.BackupCategory import eu.kanade.tachiyomi.data.backup.models.BackupHistory import eu.kanade.tachiyomi.data.backup.models.BackupManga +import eu.kanade.tachiyomi.data.backup.models.BackupPreference import eu.kanade.tachiyomi.data.backup.models.BackupSource +import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.FloatPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.IntPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.LongPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue import eu.kanade.tachiyomi.util.BackupUtil import eu.kanade.tachiyomi.util.system.createFileInCacheDir import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.isActive +import tachiyomi.core.preference.PreferenceStore import tachiyomi.domain.chapter.model.Chapter -import tachiyomi.domain.chapter.repository.ChapterRepository import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.track.model.Track @@ -30,8 +37,8 @@ class BackupRestorer( private val notifier: BackupNotifier, ) { private val updateManga: UpdateManga = Injekt.get() - private val chapterRepository: ChapterRepository = Injekt.get() private val fetchInterval: FetchInterval = Injekt.get() + private val preferenceStore: PreferenceStore = Injekt.get() private var now = ZonedDateTime.now() private var currentFetchWindow = fetchInterval.getWindow(now) @@ -106,6 +113,8 @@ class BackupRestorer( currentFetchWindow = fetchInterval.getWindow(now) return coroutineScope { + restoreAppPreferences(backup.backupPreferences) + // Restore individual manga backup.backupManga.forEach { if (!isActive) { @@ -115,6 +124,7 @@ class BackupRestorer( restoreManga(it, backup.backupCategories, sync) } // TODO: optionally trigger online library + tracker update + true } } @@ -200,6 +210,45 @@ class BackupRestorer( backupManager.restoreTracking(manga, tracks) } + private fun restoreAppPreferences(preferences: List) { + val prefs = preferenceStore.getAll() + + preferences.forEach { (key, value) -> + when (value) { + is IntPreferenceValue -> { + if (prefs[key] is Int?) { + preferenceStore.getInt(key).set(value.value) + } + } + is LongPreferenceValue -> { + if (prefs[key] is Long?) { + preferenceStore.getLong(key).set(value.value) + } + } + is FloatPreferenceValue -> { + if (prefs[key] is Float?) { + preferenceStore.getFloat(key).set(value.value) + } + } + is StringPreferenceValue -> { + if (prefs[key] is String?) { + preferenceStore.getString(key).set(value.value) + } + } + is BooleanPreferenceValue -> { + if (prefs[key] is Boolean?) { + preferenceStore.getBoolean(key).set(value.value) + } + } + is StringSetPreferenceValue -> { + if (prefs[key] is Set<*>?) { + preferenceStore.getStringSet(key).set(value.value) + } + } + } + } + } + /** * Called to update dialog in [BackupConst] * diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt index 14d4dd0ae..db9047f0d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt @@ -11,9 +11,9 @@ import java.util.Locale data class Backup( @ProtoNumber(1) val backupManga: List, @ProtoNumber(2) var backupCategories: List = emptyList(), - // Bump by 100 to specify this is a 0.x value @ProtoNumber(100) var backupBrokenSources: List = emptyList(), @ProtoNumber(101) var backupSources: List = emptyList(), + @ProtoNumber(104) var backupPreferences: List = emptyList(), ) { companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt index 8d93a0b32..c27c86fec 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt @@ -9,7 +9,6 @@ class BackupCategory( @ProtoNumber(1) var name: String, @ProtoNumber(2) var order: Long = 0, // @ProtoNumber(3) val updateInterval: Int = 0, 1.x value not used in 0.x - // Bump by 100 to specify this is a 0.x value @ProtoNumber(100) var flags: Long = 0, ) { fun getCategory(): Category { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt new file mode 100644 index 000000000..791c9706f --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt @@ -0,0 +1,31 @@ +package eu.kanade.tachiyomi.data.backup.models + +import kotlinx.serialization.Serializable +import kotlinx.serialization.protobuf.ProtoNumber + +@Serializable +data class BackupPreference( + @ProtoNumber(1) val key: String, + @ProtoNumber(2) val value: PreferenceValue, +) + +@Serializable +sealed class PreferenceValue + +@Serializable +data class IntPreferenceValue(val value: Int) : PreferenceValue() + +@Serializable +data class LongPreferenceValue(val value: Long) : PreferenceValue() + +@Serializable +data class FloatPreferenceValue(val value: Float) : PreferenceValue() + +@Serializable +data class StringPreferenceValue(val value: String) : PreferenceValue() + +@Serializable +data class BooleanPreferenceValue(val value: Boolean) : PreferenceValue() + +@Serializable +data class StringSetPreferenceValue(val value: Set) : PreferenceValue() diff --git a/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt b/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt index a0f2f335c..21f5b1d30 100644 --- a/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt +++ b/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt @@ -12,6 +12,7 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn +import tachiyomi.core.util.system.logcat sealed class AndroidPreference( private val preferences: SharedPreferences, @@ -29,7 +30,13 @@ sealed class AndroidPreference( } override fun get(): T { - return read(preferences, key, defaultValue) + return try { + read(preferences, key, defaultValue) + } catch (e: ClassCastException) { + logcat { "Invalid value for $key; deleting" } + delete() + defaultValue + } } override fun set(value: T) { diff --git a/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt b/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt index c59652da5..67e4db7fc 100644 --- a/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt +++ b/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt @@ -60,6 +60,10 @@ class AndroidPreferenceStore( deserializer = deserializer, ) } + + override fun getAll(): Map { + return sharedPreferences.all ?: emptyMap() + } } private val SharedPreferences.keyFlow diff --git a/core/src/main/java/tachiyomi/core/preference/PreferenceStore.kt b/core/src/main/java/tachiyomi/core/preference/PreferenceStore.kt index f8cc9f890..5b0e9da9b 100644 --- a/core/src/main/java/tachiyomi/core/preference/PreferenceStore.kt +++ b/core/src/main/java/tachiyomi/core/preference/PreferenceStore.kt @@ -20,6 +20,8 @@ interface PreferenceStore { serializer: (T) -> String, deserializer: (String) -> T, ): Preference + + fun getAll(): Map } inline fun > PreferenceStore.getEnum( diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 8821087b2..410ec9ec2 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -493,6 +493,7 @@ Backup is already in progress What do you want to backup? + App settings Creating backup Backup failed Storage permissions not granted From 730f3a6e5209197c7a026c36371545d5aef85851 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 8 Oct 2023 11:07:42 -0400 Subject: [PATCH 51/59] Exclude tracker credentials in backups --- app/build.gradle.kts | 2 +- .../domain/track/service/TrackPreferences.kt | 7 +++--- .../java/eu/kanade/tachiyomi/Migrations.kt | 14 +++++++++++ .../tachiyomi/data/backup/BackupManager.kt | 25 +++++++++++-------- .../tachiyomi/core/preference/Preference.kt | 18 +++++++++++++ i18n/src/main/res/values/strings.xml | 2 +- 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5b9540486..5f8b6166e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,7 +22,7 @@ android { defaultConfig { applicationId = "eu.kanade.tachiyomi" - versionCode = 106 + versionCode = 107 versionName = "0.14.6" buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") diff --git a/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt b/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt index 418d794b9..c7fb47581 100644 --- a/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt +++ b/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt @@ -2,6 +2,7 @@ package eu.kanade.domain.track.service import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.anilist.Anilist +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore class TrackPreferences( @@ -24,10 +25,10 @@ class TrackPreferences( fun autoUpdateTrack() = preferenceStore.getBoolean("pref_auto_update_manga_sync_key", true) companion object { - fun trackUsername(syncId: Long) = "pref_mangasync_username_$syncId" + fun trackUsername(syncId: Long) = Preference.privateKey("pref_mangasync_username_$syncId") - private fun trackPassword(syncId: Long) = "pref_mangasync_password_$syncId" + private fun trackPassword(syncId: Long) = Preference.privateKey("pref_mangasync_password_$syncId") - private fun trackToken(syncId: Long) = "track_token_$syncId" + private fun trackToken(syncId: Long) = Preference.privateKey("track_token_$syncId") } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index c3b4db069..f341e26a6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.isReleaseBuildType import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.workManager +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.TriState import tachiyomi.core.preference.getAndSet @@ -381,6 +382,19 @@ object Migrations { uiPreferences.relativeTime().set(false) } } + if (oldVersion < 107) { + preferenceStore.getAll() + .filter { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") } + .forEach { (key, value) -> + if (value is String) { + preferenceStore + .getString(Preference.privateKey(key)) + .set(value) + + preferenceStore.getString(key).delete() + } + } + } return true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index 941878109..1ae5ec202 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt @@ -39,6 +39,7 @@ import logcat.LogPriority import okio.buffer import okio.gzip import okio.sink +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.util.system.logcat import tachiyomi.data.DatabaseHandler @@ -235,19 +236,21 @@ class BackupManager( private fun backupAppPreferences(flags: Int): List { if (flags and BACKUP_APP_PREFS_MASK != BACKUP_APP_PREFS) return emptyList() - return preferenceStore.getAll().mapNotNull { (key, value) -> - when (value) { - is Int -> BackupPreference(key, IntPreferenceValue(value)) - is Long -> BackupPreference(key, LongPreferenceValue(value)) - is Float -> BackupPreference(key, FloatPreferenceValue(value)) - is String -> BackupPreference(key, StringPreferenceValue(value)) - is Boolean -> BackupPreference(key, BooleanPreferenceValue(value)) - is Set<*> -> (value as? Set)?.let { - BackupPreference(key, StringSetPreferenceValue(it)) + return preferenceStore.getAll() + .filterKeys { !Preference.isPrivate(it) } + .mapNotNull { (key, value) -> + when (value) { + is Int -> BackupPreference(key, IntPreferenceValue(value)) + is Long -> BackupPreference(key, LongPreferenceValue(value)) + is Float -> BackupPreference(key, FloatPreferenceValue(value)) + is String -> BackupPreference(key, StringPreferenceValue(value)) + is Boolean -> BackupPreference(key, BooleanPreferenceValue(value)) + is Set<*> -> (value as? Set)?.let { + BackupPreference(key, StringSetPreferenceValue(it)) + } + else -> null } - else -> null } - } } internal suspend fun restoreExistingManga(manga: Manga, dbManga: Mangas): Manga { diff --git a/core/src/main/java/tachiyomi/core/preference/Preference.kt b/core/src/main/java/tachiyomi/core/preference/Preference.kt index e76ea23d4..e10f6e7fe 100644 --- a/core/src/main/java/tachiyomi/core/preference/Preference.kt +++ b/core/src/main/java/tachiyomi/core/preference/Preference.kt @@ -21,6 +21,24 @@ interface Preference { fun changes(): Flow fun stateIn(scope: CoroutineScope): StateFlow + + val isPrivate: Boolean + get() = key().startsWith(PRIVATE_PREFIX) + + companion object { + /** + * A preference that should not be exposed in places like backups. + */ + fun isPrivate(key: String): Boolean { + return key.startsWith(PRIVATE_PREFIX) + } + + fun privateKey(key: String): String { + return "${PRIVATE_PREFIX}$key" + } + + private const val PRIVATE_PREFIX = "__PRIVATE_" + } } inline fun Preference.getAndSet(crossinline block: (T) -> R) = set( diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 410ec9ec2..caebd66b7 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -504,7 +504,7 @@ Restoring backup Restoring backup failed Canceled restore - You should keep copies of backups in other places as well. + You should keep copies of backups in other places as well. Backups may contain sensitive data including any stored passwords; be careful if sharing. Syncing library From 0f42b9f1544b188362d1c0046c8ff853827ed270 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 8 Oct 2023 16:02:03 -0400 Subject: [PATCH 52/59] Add source preferences to backups Closes #1857 Co-authored-by: jmir1 --- .../settings/screen/SettingsBackupScreen.kt | 1 + .../tachiyomi/data/backup/BackupConst.kt | 5 +++- .../tachiyomi/data/backup/BackupManager.kt | 29 +++++++++++++++++-- .../tachiyomi/data/backup/BackupRestorer.kt | 28 ++++++++++++------ .../tachiyomi/data/backup/models/Backup.kt | 1 + .../data/backup/models/BackupPreference.kt | 6 ++++ .../core/preference/AndroidPreferenceStore.kt | 3 +- i18n/src/main/res/values/strings.xml | 1 + .../tachiyomi/source/ConfigurableSource.kt | 5 +++- 9 files changed, 63 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt index a5adfb75d..ec6b2a1da 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt @@ -148,6 +148,7 @@ object SettingsBackupScreen : SearchableSettings { BackupConst.BACKUP_TRACK to R.string.track, BackupConst.BACKUP_HISTORY to R.string.history, BackupConst.BACKUP_APP_PREFS to R.string.app_settings, + BackupConst.BACKUP_SOURCE_PREFS to R.string.source_settings, ) } val flags = remember { choices.keys.toMutableStateList() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt index a137046e4..6bc4771dc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt @@ -17,5 +17,8 @@ internal object BackupConst { const val BACKUP_APP_PREFS = 0x10 const val BACKUP_APP_PREFS_MASK = 0x10 - const val BACKUP_ALL = 0x1F + const val BACKUP_SOURCE_PREFS = 0x20 + const val BACKUP_SOURCE_PREFS_MASK = 0x20 + + const val BACKUP_ALL = 0x3F } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index 1ae5ec202..890f32bbb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt @@ -12,12 +12,15 @@ import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER_MASK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS_MASK import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY_MASK import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK_MASK import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.backup.models.BackupCategory +import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences import eu.kanade.tachiyomi.data.backup.models.BackupHistory import eu.kanade.tachiyomi.data.backup.models.BackupManga import eu.kanade.tachiyomi.data.backup.models.BackupPreference @@ -32,7 +35,10 @@ import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue import eu.kanade.tachiyomi.data.backup.models.backupCategoryMapper import eu.kanade.tachiyomi.data.backup.models.backupChapterMapper import eu.kanade.tachiyomi.data.backup.models.backupTrackMapper +import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.model.copyFrom +import eu.kanade.tachiyomi.source.preferenceKey +import eu.kanade.tachiyomi.source.sourcePreferences import eu.kanade.tachiyomi.util.system.hasPermission import kotlinx.serialization.protobuf.ProtoBuf import logcat.LogPriority @@ -94,6 +100,7 @@ class BackupManager( emptyList(), prepExtensionInfoForSync(databaseManga), backupAppPreferences(flags), + backupSourcePreferences(flags), ) var file: UniFile? = null @@ -232,12 +239,28 @@ class BackupManager( return mangaObject } - @Suppress("UNCHECKED_CAST") private fun backupAppPreferences(flags: Int): List { if (flags and BACKUP_APP_PREFS_MASK != BACKUP_APP_PREFS) return emptyList() - return preferenceStore.getAll() - .filterKeys { !Preference.isPrivate(it) } + return preferenceStore.getAll().toBackupPreferences() + } + + private fun backupSourcePreferences(flags: Int): List { + if (flags and BACKUP_SOURCE_PREFS_MASK != BACKUP_SOURCE_PREFS) return emptyList() + + return sourceManager.getOnlineSources() + .filterIsInstance() + .map { + BackupSourcePreferences( + it.preferenceKey(), + it.sourcePreferences().all.toBackupPreferences() + ) + } + } + + @Suppress("UNCHECKED_CAST") + private fun Map.toBackupPreferences(): List { + return this.filterKeys { !Preference.isPrivate(it) } .mapNotNull { (key, value) -> when (value) { is Int -> BackupPreference(key, IntPreferenceValue(value)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt index 1c0558b4d..2cd4bbc4a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt @@ -9,16 +9,19 @@ import eu.kanade.tachiyomi.data.backup.models.BackupHistory import eu.kanade.tachiyomi.data.backup.models.BackupManga import eu.kanade.tachiyomi.data.backup.models.BackupPreference import eu.kanade.tachiyomi.data.backup.models.BackupSource +import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue import eu.kanade.tachiyomi.data.backup.models.FloatPreferenceValue import eu.kanade.tachiyomi.data.backup.models.IntPreferenceValue import eu.kanade.tachiyomi.data.backup.models.LongPreferenceValue import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue +import eu.kanade.tachiyomi.source.sourcePreferences import eu.kanade.tachiyomi.util.BackupUtil import eu.kanade.tachiyomi.util.system.createFileInCacheDir import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.isActive +import tachiyomi.core.preference.AndroidPreferenceStore import tachiyomi.core.preference.PreferenceStore import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.interactor.FetchInterval @@ -114,6 +117,7 @@ class BackupRestorer( return coroutineScope { restoreAppPreferences(backup.backupPreferences) + restoreSourcePreferences(backup.backupSourcePreferences) // Restore individual manga backup.backupManga.forEach { @@ -211,9 +215,22 @@ class BackupRestorer( } private fun restoreAppPreferences(preferences: List) { - val prefs = preferenceStore.getAll() + restorePreferences(preferences, preferenceStore) + } - preferences.forEach { (key, value) -> + private fun restoreSourcePreferences(preferences: List) { + preferences.forEach { + val sourcePrefs = AndroidPreferenceStore(context, sourcePreferences(it.sourceKey)) + restorePreferences(it.prefs, sourcePrefs) + } + } + + private fun restorePreferences( + toRestore: List, + preferenceStore: PreferenceStore, + ) { + val prefs = preferenceStore.getAll() + toRestore.forEach { (key, value) -> when (value) { is IntPreferenceValue -> { if (prefs[key] is Int?) { @@ -249,13 +266,6 @@ class BackupRestorer( } } - /** - * Called to update dialog in [BackupConst] - * - * @param progress restore progress - * @param amount total restoreAmount of manga - * @param title title of restored manga - */ private fun showRestoreProgress(progress: Int, amount: Int, title: String, contentTitle: String) { notifier.showRestoreProgress(title, contentTitle, progress, amount) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt index db9047f0d..0bfe17e59 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt @@ -14,6 +14,7 @@ data class Backup( @ProtoNumber(100) var backupBrokenSources: List = emptyList(), @ProtoNumber(101) var backupSources: List = emptyList(), @ProtoNumber(104) var backupPreferences: List = emptyList(), + @ProtoNumber(105) var backupSourcePreferences: List = emptyList(), ) { companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt index 791c9706f..3884f37e3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt @@ -9,6 +9,12 @@ data class BackupPreference( @ProtoNumber(2) val value: PreferenceValue, ) +@Serializable +data class BackupSourcePreferences( + @ProtoNumber(1) val sourceKey: String, + @ProtoNumber(2) val prefs: List, +) + @Serializable sealed class PreferenceValue diff --git a/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt b/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt index 67e4db7fc..b24fa5dcc 100644 --- a/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt +++ b/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt @@ -15,10 +15,9 @@ import tachiyomi.core.preference.AndroidPreference.StringSetPrimitive class AndroidPreferenceStore( context: Context, + private val sharedPreferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context), ) : PreferenceStore { - private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - private val keyFlow = sharedPreferences.keyFlow override fun getString(key: String, defaultValue: String): Preference { diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index caebd66b7..ac21d13f6 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -494,6 +494,7 @@ Backup is already in progress What do you want to backup? App settings + Source settings Creating backup Backup failed Storage permissions not granted diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt index ea5eb848e..db9a98520 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt @@ -19,8 +19,11 @@ interface ConfigurableSource : Source { fun setupPreferenceScreen(screen: PreferenceScreen) } -private fun ConfigurableSource.preferenceKey(): String = "source_$id" +fun ConfigurableSource.preferenceKey(): String = "source_$id" // TODO: use getSourcePreferences once all extensions are on ext-lib 1.5 fun ConfigurableSource.sourcePreferences(): SharedPreferences = Injekt.get().getSharedPreferences(preferenceKey(), Context.MODE_PRIVATE) + +fun sourcePreferences(key: String): SharedPreferences = + Injekt.get().getSharedPreferences(key, Context.MODE_PRIVATE) From 6dab94a9371ad3eac0488c5f105e8e38c6c4e232 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 8 Oct 2023 16:08:01 -0400 Subject: [PATCH 53/59] Move backup restoring functions from BackupManager to BackupRestorer --- .../tachiyomi/data/backup/BackupCreateJob.kt | 2 +- .../tachiyomi/data/backup/BackupCreator.kt | 268 ++++++++ .../tachiyomi/data/backup/BackupManager.kt | 646 ------------------ .../tachiyomi/data/backup/BackupRestorer.kt | 402 ++++++++++- .../eu/kanade/tachiyomi/util/BackupUtil.kt | 6 +- 5 files changed, 662 insertions(+), 662 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateJob.kt index 6f960edec..875039e86 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateJob.kt @@ -49,7 +49,7 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete } return try { - val location = BackupManager(context).createBackup(uri, flags, isAutoBackup) + val location = BackupCreator(context).createBackup(uri, flags, isAutoBackup) if (!isAutoBackup) notifier.showBackupComplete(UniFile.fromUri(context, location.toUri())) Result.success() } catch (e: Exception) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt new file mode 100644 index 000000000..b70df331f --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt @@ -0,0 +1,268 @@ +package eu.kanade.tachiyomi.data.backup + +import android.Manifest +import android.content.Context +import android.net.Uri +import com.hippo.unifile.UniFile +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_APP_PREFS +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_APP_PREFS_MASK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER_MASK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY_MASK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS_MASK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK_MASK +import eu.kanade.tachiyomi.data.backup.models.Backup +import eu.kanade.tachiyomi.data.backup.models.BackupCategory +import eu.kanade.tachiyomi.data.backup.models.BackupHistory +import eu.kanade.tachiyomi.data.backup.models.BackupManga +import eu.kanade.tachiyomi.data.backup.models.BackupPreference +import eu.kanade.tachiyomi.data.backup.models.BackupSerializer +import eu.kanade.tachiyomi.data.backup.models.BackupSource +import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences +import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.FloatPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.IntPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.LongPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue +import eu.kanade.tachiyomi.data.backup.models.backupCategoryMapper +import eu.kanade.tachiyomi.data.backup.models.backupChapterMapper +import eu.kanade.tachiyomi.data.backup.models.backupTrackMapper +import eu.kanade.tachiyomi.source.ConfigurableSource +import eu.kanade.tachiyomi.source.preferenceKey +import eu.kanade.tachiyomi.source.sourcePreferences +import eu.kanade.tachiyomi.util.system.hasPermission +import kotlinx.serialization.protobuf.ProtoBuf +import logcat.LogPriority +import okio.buffer +import okio.gzip +import okio.sink +import tachiyomi.core.preference.Preference +import tachiyomi.core.preference.PreferenceStore +import tachiyomi.core.util.system.logcat +import tachiyomi.data.DatabaseHandler +import tachiyomi.domain.backup.service.BackupPreferences +import tachiyomi.domain.category.interactor.GetCategories +import tachiyomi.domain.category.model.Category +import tachiyomi.domain.history.interactor.GetHistory +import tachiyomi.domain.manga.interactor.GetFavorites +import tachiyomi.domain.manga.model.Manga +import tachiyomi.domain.source.service.SourceManager +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import java.io.FileOutputStream + +class BackupCreator( + private val context: Context, +) { + + private val handler: DatabaseHandler = Injekt.get() + private val sourceManager: SourceManager = Injekt.get() + private val backupPreferences: BackupPreferences = Injekt.get() + private val getCategories: GetCategories = Injekt.get() + private val getFavorites: GetFavorites = Injekt.get() + private val getHistory: GetHistory = Injekt.get() + private val preferenceStore: PreferenceStore = Injekt.get() + + internal val parser = ProtoBuf + + /** + * Create backup file. + * + * @param uri path of Uri + * @param isAutoBackup backup called from scheduled backup job + */ + suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String { + if (!context.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + throw IllegalStateException(context.getString(R.string.missing_storage_permission)) + } + + val databaseManga = getFavorites.await() + val backup = Backup( + backupMangas(databaseManga, flags), + backupCategories(flags), + emptyList(), + prepExtensionInfoForSync(databaseManga), + backupAppPreferences(flags), + backupSourcePreferences(flags), + ) + + var file: UniFile? = null + try { + file = ( + if (isAutoBackup) { + // Get dir of file and create + var dir = UniFile.fromUri(context, uri) + dir = dir.createDirectory("automatic") + + // Delete older backups + val numberOfBackups = backupPreferences.numberOfBackups().get() + dir.listFiles { _, filename -> Backup.filenameRegex.matches(filename) } + .orEmpty() + .sortedByDescending { it.name } + .drop(numberOfBackups - 1) + .forEach { it.delete() } + + // Create new file to place backup + dir.createFile(Backup.getFilename()) + } else { + UniFile.fromUri(context, uri) + } + ) + ?: throw Exception(context.getString(R.string.create_backup_file_error)) + + if (!file.isFile) { + throw IllegalStateException("Failed to get handle on a backup file") + } + + val byteArray = parser.encodeToByteArray(BackupSerializer, backup) + if (byteArray.isEmpty()) { + throw IllegalStateException(context.getString(R.string.empty_backup_error)) + } + + file.openOutputStream().also { + // Force overwrite old file + (it as? FileOutputStream)?.channel?.truncate(0) + }.sink().gzip().buffer().use { it.write(byteArray) } + val fileUri = file.uri + + // Make sure it's a valid backup file + BackupFileValidator().validate(context, fileUri) + + return fileUri.toString() + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + file?.delete() + throw e + } + } + + private fun prepExtensionInfoForSync(mangas: List): List { + return mangas + .asSequence() + .map(Manga::source) + .distinct() + .map(sourceManager::getOrStub) + .map(BackupSource::copyFrom) + .toList() + } + + /** + * Backup the categories of library + * + * @return list of [BackupCategory] to be backed up + */ + private suspend fun backupCategories(options: Int): List { + // Check if user wants category information in backup + return if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) { + getCategories.await() + .filterNot(Category::isSystemCategory) + .map(backupCategoryMapper) + } else { + emptyList() + } + } + + private suspend fun backupMangas(mangas: List, flags: Int): List { + return mangas.map { + backupManga(it, flags) + } + } + + /** + * Convert a manga to Json + * + * @param manga manga that gets converted + * @param options options for the backup + * @return [BackupManga] containing manga in a serializable form + */ + private suspend fun backupManga(manga: Manga, options: Int): BackupManga { + // Entry for this manga + val mangaObject = BackupManga.copyFrom(manga) + + // Check if user wants chapter information in backup + if (options and BACKUP_CHAPTER_MASK == BACKUP_CHAPTER) { + // Backup all the chapters + val chapters = handler.awaitList { chaptersQueries.getChaptersByMangaId(manga.id, backupChapterMapper) } + if (chapters.isNotEmpty()) { + mangaObject.chapters = chapters + } + } + + // Check if user wants category information in backup + if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) { + // Backup categories for this manga + val categoriesForManga = getCategories.await(manga.id) + if (categoriesForManga.isNotEmpty()) { + mangaObject.categories = categoriesForManga.map { it.order } + } + } + + // Check if user wants track information in backup + if (options and BACKUP_TRACK_MASK == BACKUP_TRACK) { + val tracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id, backupTrackMapper) } + if (tracks.isNotEmpty()) { + mangaObject.tracking = tracks + } + } + + // Check if user wants history information in backup + if (options and BACKUP_HISTORY_MASK == BACKUP_HISTORY) { + val historyByMangaId = getHistory.await(manga.id) + if (historyByMangaId.isNotEmpty()) { + val history = historyByMangaId.map { history -> + val chapter = handler.awaitOne { chaptersQueries.getChapterById(history.chapterId) } + BackupHistory(chapter.url, history.readAt?.time ?: 0L, history.readDuration) + } + if (history.isNotEmpty()) { + mangaObject.history = history + } + } + } + + return mangaObject + } + + private fun backupAppPreferences(flags: Int): List { + if (flags and BACKUP_APP_PREFS_MASK != BACKUP_APP_PREFS) return emptyList() + + return preferenceStore.getAll().toBackupPreferences() + } + + private fun backupSourcePreferences(flags: Int): List { + if (flags and BACKUP_SOURCE_PREFS_MASK != BACKUP_SOURCE_PREFS) return emptyList() + + return sourceManager.getOnlineSources() + .filterIsInstance() + .map { + BackupSourcePreferences( + it.preferenceKey(), + it.sourcePreferences().all.toBackupPreferences(), + ) + } + } + + @Suppress("UNCHECKED_CAST") + private fun Map.toBackupPreferences(): List { + return this.filterKeys { !Preference.isPrivate(it) } + .mapNotNull { (key, value) -> + when (value) { + is Int -> BackupPreference(key, IntPreferenceValue(value)) + is Long -> BackupPreference(key, LongPreferenceValue(value)) + is Float -> BackupPreference(key, FloatPreferenceValue(value)) + is String -> BackupPreference(key, StringPreferenceValue(value)) + is Boolean -> BackupPreference(key, BooleanPreferenceValue(value)) + is Set<*> -> (value as? Set)?.let { + BackupPreference(key, StringSetPreferenceValue(it)) + } + else -> null + } + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt deleted file mode 100644 index 890f32bbb..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ /dev/null @@ -1,646 +0,0 @@ -package eu.kanade.tachiyomi.data.backup - -import android.Manifest -import android.content.Context -import android.net.Uri -import com.hippo.unifile.UniFile -import eu.kanade.domain.chapter.model.copyFrom -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_APP_PREFS -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_APP_PREFS_MASK -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER_MASK -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS_MASK -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY_MASK -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK -import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK_MASK -import eu.kanade.tachiyomi.data.backup.models.Backup -import eu.kanade.tachiyomi.data.backup.models.BackupCategory -import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences -import eu.kanade.tachiyomi.data.backup.models.BackupHistory -import eu.kanade.tachiyomi.data.backup.models.BackupManga -import eu.kanade.tachiyomi.data.backup.models.BackupPreference -import eu.kanade.tachiyomi.data.backup.models.BackupSerializer -import eu.kanade.tachiyomi.data.backup.models.BackupSource -import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue -import eu.kanade.tachiyomi.data.backup.models.FloatPreferenceValue -import eu.kanade.tachiyomi.data.backup.models.IntPreferenceValue -import eu.kanade.tachiyomi.data.backup.models.LongPreferenceValue -import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue -import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue -import eu.kanade.tachiyomi.data.backup.models.backupCategoryMapper -import eu.kanade.tachiyomi.data.backup.models.backupChapterMapper -import eu.kanade.tachiyomi.data.backup.models.backupTrackMapper -import eu.kanade.tachiyomi.source.ConfigurableSource -import eu.kanade.tachiyomi.source.model.copyFrom -import eu.kanade.tachiyomi.source.preferenceKey -import eu.kanade.tachiyomi.source.sourcePreferences -import eu.kanade.tachiyomi.util.system.hasPermission -import kotlinx.serialization.protobuf.ProtoBuf -import logcat.LogPriority -import okio.buffer -import okio.gzip -import okio.sink -import tachiyomi.core.preference.Preference -import tachiyomi.core.preference.PreferenceStore -import tachiyomi.core.util.system.logcat -import tachiyomi.data.DatabaseHandler -import tachiyomi.data.Manga_sync -import tachiyomi.data.Mangas -import tachiyomi.data.UpdateStrategyColumnAdapter -import tachiyomi.domain.backup.service.BackupPreferences -import tachiyomi.domain.category.interactor.GetCategories -import tachiyomi.domain.category.model.Category -import tachiyomi.domain.history.interactor.GetHistory -import tachiyomi.domain.history.model.HistoryUpdate -import tachiyomi.domain.library.service.LibraryPreferences -import tachiyomi.domain.manga.interactor.GetFavorites -import tachiyomi.domain.manga.model.Manga -import tachiyomi.domain.source.service.SourceManager -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import java.io.FileOutputStream -import java.util.Date -import kotlin.math.max - -class BackupManager( - private val context: Context, -) { - - private val handler: DatabaseHandler = Injekt.get() - private val sourceManager: SourceManager = Injekt.get() - private val backupPreferences: BackupPreferences = Injekt.get() - private val libraryPreferences: LibraryPreferences = Injekt.get() - private val getCategories: GetCategories = Injekt.get() - private val getFavorites: GetFavorites = Injekt.get() - private val getHistory: GetHistory = Injekt.get() - private val preferenceStore: PreferenceStore = Injekt.get() - - internal val parser = ProtoBuf - - /** - * Create backup file from database - * - * @param uri path of Uri - * @param isAutoBackup backup called from scheduled backup job - */ - suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String { - if (!context.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { - throw IllegalStateException(context.getString(R.string.missing_storage_permission)) - } - - val databaseManga = getFavorites.await() - val backup = Backup( - backupMangas(databaseManga, flags), - backupCategories(flags), - emptyList(), - prepExtensionInfoForSync(databaseManga), - backupAppPreferences(flags), - backupSourcePreferences(flags), - ) - - var file: UniFile? = null - try { - file = ( - if (isAutoBackup) { - // Get dir of file and create - var dir = UniFile.fromUri(context, uri) - dir = dir.createDirectory("automatic") - - // Delete older backups - val numberOfBackups = backupPreferences.numberOfBackups().get() - dir.listFiles { _, filename -> Backup.filenameRegex.matches(filename) } - .orEmpty() - .sortedByDescending { it.name } - .drop(numberOfBackups - 1) - .forEach { it.delete() } - - // Create new file to place backup - dir.createFile(Backup.getFilename()) - } else { - UniFile.fromUri(context, uri) - } - ) - ?: throw Exception(context.getString(R.string.create_backup_file_error)) - - if (!file.isFile) { - throw IllegalStateException("Failed to get handle on a backup file") - } - - val byteArray = parser.encodeToByteArray(BackupSerializer, backup) - if (byteArray.isEmpty()) { - throw IllegalStateException(context.getString(R.string.empty_backup_error)) - } - - file.openOutputStream().also { - // Force overwrite old file - (it as? FileOutputStream)?.channel?.truncate(0) - }.sink().gzip().buffer().use { it.write(byteArray) } - val fileUri = file.uri - - // Make sure it's a valid backup file - BackupFileValidator().validate(context, fileUri) - - return fileUri.toString() - } catch (e: Exception) { - logcat(LogPriority.ERROR, e) - file?.delete() - throw e - } - } - - private fun prepExtensionInfoForSync(mangas: List): List { - return mangas - .asSequence() - .map(Manga::source) - .distinct() - .map(sourceManager::getOrStub) - .map(BackupSource::copyFrom) - .toList() - } - - /** - * Backup the categories of library - * - * @return list of [BackupCategory] to be backed up - */ - private suspend fun backupCategories(options: Int): List { - // Check if user wants category information in backup - return if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) { - getCategories.await() - .filterNot(Category::isSystemCategory) - .map(backupCategoryMapper) - } else { - emptyList() - } - } - - private suspend fun backupMangas(mangas: List, flags: Int): List { - return mangas.map { - backupManga(it, flags) - } - } - - /** - * Convert a manga to Json - * - * @param manga manga that gets converted - * @param options options for the backup - * @return [BackupManga] containing manga in a serializable form - */ - private suspend fun backupManga(manga: Manga, options: Int): BackupManga { - // Entry for this manga - val mangaObject = BackupManga.copyFrom(manga) - - // Check if user wants chapter information in backup - if (options and BACKUP_CHAPTER_MASK == BACKUP_CHAPTER) { - // Backup all the chapters - val chapters = handler.awaitList { chaptersQueries.getChaptersByMangaId(manga.id, backupChapterMapper) } - if (chapters.isNotEmpty()) { - mangaObject.chapters = chapters - } - } - - // Check if user wants category information in backup - if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) { - // Backup categories for this manga - val categoriesForManga = getCategories.await(manga.id) - if (categoriesForManga.isNotEmpty()) { - mangaObject.categories = categoriesForManga.map { it.order } - } - } - - // Check if user wants track information in backup - if (options and BACKUP_TRACK_MASK == BACKUP_TRACK) { - val tracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id, backupTrackMapper) } - if (tracks.isNotEmpty()) { - mangaObject.tracking = tracks - } - } - - // Check if user wants history information in backup - if (options and BACKUP_HISTORY_MASK == BACKUP_HISTORY) { - val historyByMangaId = getHistory.await(manga.id) - if (historyByMangaId.isNotEmpty()) { - val history = historyByMangaId.map { history -> - val chapter = handler.awaitOne { chaptersQueries.getChapterById(history.chapterId) } - BackupHistory(chapter.url, history.readAt?.time ?: 0L, history.readDuration) - } - if (history.isNotEmpty()) { - mangaObject.history = history - } - } - } - - return mangaObject - } - - private fun backupAppPreferences(flags: Int): List { - if (flags and BACKUP_APP_PREFS_MASK != BACKUP_APP_PREFS) return emptyList() - - return preferenceStore.getAll().toBackupPreferences() - } - - private fun backupSourcePreferences(flags: Int): List { - if (flags and BACKUP_SOURCE_PREFS_MASK != BACKUP_SOURCE_PREFS) return emptyList() - - return sourceManager.getOnlineSources() - .filterIsInstance() - .map { - BackupSourcePreferences( - it.preferenceKey(), - it.sourcePreferences().all.toBackupPreferences() - ) - } - } - - @Suppress("UNCHECKED_CAST") - private fun Map.toBackupPreferences(): List { - return this.filterKeys { !Preference.isPrivate(it) } - .mapNotNull { (key, value) -> - when (value) { - is Int -> BackupPreference(key, IntPreferenceValue(value)) - is Long -> BackupPreference(key, LongPreferenceValue(value)) - is Float -> BackupPreference(key, FloatPreferenceValue(value)) - is String -> BackupPreference(key, StringPreferenceValue(value)) - is Boolean -> BackupPreference(key, BooleanPreferenceValue(value)) - is Set<*> -> (value as? Set)?.let { - BackupPreference(key, StringSetPreferenceValue(it)) - } - else -> null - } - } - } - - internal suspend fun restoreExistingManga(manga: Manga, dbManga: Mangas): Manga { - var updatedManga = manga.copy(id = dbManga._id) - updatedManga = updatedManga.copyFrom(dbManga) - updateManga(updatedManga) - return updatedManga - } - - /** - * Fetches manga information - * - * @param manga manga that needs updating - * @return Updated manga info. - */ - internal suspend fun restoreNewManga(manga: Manga): Manga { - return manga.copy( - initialized = manga.description != null, - id = insertManga(manga), - ) - } - - /** - * Restore the categories from Json - * - * @param backupCategories list containing categories - */ - internal suspend fun restoreCategories(backupCategories: List) { - // Get categories from file and from db - val dbCategories = getCategories.await() - - val categories = backupCategories.map { - var category = it.getCategory() - var found = false - for (dbCategory in dbCategories) { - // If the category is already in the db, assign the id to the file's category - // and do nothing - if (category.name == dbCategory.name) { - category = category.copy(id = dbCategory.id) - found = true - break - } - } - if (!found) { - // Let the db assign the id - val id = handler.awaitOneExecutable { - categoriesQueries.insert(category.name, category.order, category.flags) - categoriesQueries.selectLastInsertedRowId() - } - category = category.copy(id = id) - } - - category - } - - libraryPreferences.categorizedDisplaySettings().set( - (dbCategories + categories) - .distinctBy { it.flags } - .size > 1, - ) - } - - /** - * Restores the categories a manga is in. - * - * @param manga the manga whose categories have to be restored. - * @param categories the categories to restore. - */ - internal suspend fun restoreCategories(manga: Manga, categories: List, backupCategories: List) { - val dbCategories = getCategories.await() - val mangaCategoriesToUpdate = mutableListOf>() - - categories.forEach { backupCategoryOrder -> - backupCategories.firstOrNull { - it.order == backupCategoryOrder.toLong() - }?.let { backupCategory -> - dbCategories.firstOrNull { dbCategory -> - dbCategory.name == backupCategory.name - }?.let { dbCategory -> - mangaCategoriesToUpdate.add(Pair(manga.id, dbCategory.id)) - } - } - } - - // Update database - if (mangaCategoriesToUpdate.isNotEmpty()) { - handler.await(true) { - mangas_categoriesQueries.deleteMangaCategoryByMangaId(manga.id) - mangaCategoriesToUpdate.forEach { (mangaId, categoryId) -> - mangas_categoriesQueries.insert(mangaId, categoryId) - } - } - } - } - - /** - * Restore history from Json - * - * @param history list containing history to be restored - */ - internal suspend fun restoreHistory(history: List) { - // List containing history to be updated - val toUpdate = mutableListOf() - for ((url, lastRead, readDuration) in history) { - var dbHistory = handler.awaitOneOrNull { historyQueries.getHistoryByChapterUrl(url) } - // Check if history already in database and update - if (dbHistory != null) { - dbHistory = dbHistory.copy( - last_read = Date(max(lastRead, dbHistory.last_read?.time ?: 0L)), - time_read = max(readDuration, dbHistory.time_read) - dbHistory.time_read, - ) - toUpdate.add( - HistoryUpdate( - chapterId = dbHistory.chapter_id, - readAt = dbHistory.last_read!!, - sessionReadDuration = dbHistory.time_read, - ), - ) - } else { - // If not in database create - handler - .awaitOneOrNull { chaptersQueries.getChapterByUrl(url) } - ?.let { - toUpdate.add( - HistoryUpdate( - chapterId = it._id, - readAt = Date(lastRead), - sessionReadDuration = readDuration, - ), - ) - } - } - } - handler.await(true) { - toUpdate.forEach { payload -> - historyQueries.upsert( - payload.chapterId, - payload.readAt, - payload.sessionReadDuration, - ) - } - } - } - - /** - * Restores the sync of a manga. - * - * @param manga the manga whose sync have to be restored. - * @param tracks the track list to restore. - */ - internal suspend fun restoreTracking(manga: Manga, tracks: List) { - // Get tracks from database - val dbTracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id) } - val toUpdate = mutableListOf() - val toInsert = mutableListOf() - - tracks - // Fix foreign keys with the current manga id - .map { it.copy(mangaId = manga.id) } - .forEach { track -> - var isInDatabase = false - for (dbTrack in dbTracks) { - if (track.syncId == dbTrack.sync_id) { - // The sync is already in the db, only update its fields - var temp = dbTrack - if (track.remoteId != dbTrack.remote_id) { - temp = temp.copy(remote_id = track.remoteId) - } - if (track.libraryId != dbTrack.library_id) { - temp = temp.copy(library_id = track.libraryId) - } - temp = temp.copy(last_chapter_read = max(dbTrack.last_chapter_read, track.lastChapterRead)) - isInDatabase = true - toUpdate.add(temp) - break - } - } - if (!isInDatabase) { - // Insert new sync. Let the db assign the id - toInsert.add(track.copy(id = 0)) - } - } - - // Update database - if (toUpdate.isNotEmpty()) { - handler.await(true) { - toUpdate.forEach { track -> - manga_syncQueries.update( - track.manga_id, - track.sync_id, - track.remote_id, - track.library_id, - track.title, - track.last_chapter_read, - track.total_chapters, - track.status, - track.score, - track.remote_url, - track.start_date, - track.finish_date, - track._id, - ) - } - } - } - if (toInsert.isNotEmpty()) { - handler.await(true) { - toInsert.forEach { track -> - manga_syncQueries.insert( - track.mangaId, - track.syncId, - track.remoteId, - track.libraryId, - track.title, - track.lastChapterRead, - track.totalChapters, - track.status, - track.score, - track.remoteUrl, - track.startDate, - track.finishDate, - ) - } - } - } - } - - internal suspend fun restoreChapters(manga: Manga, chapters: List) { - val dbChapters = handler.awaitList { chaptersQueries.getChaptersByMangaId(manga.id) } - - val processed = chapters.map { chapter -> - var updatedChapter = chapter - val dbChapter = dbChapters.find { it.url == updatedChapter.url } - if (dbChapter != null) { - updatedChapter = updatedChapter.copy(id = dbChapter._id) - updatedChapter = updatedChapter.copyFrom(dbChapter) - if (dbChapter.read && !updatedChapter.read) { - updatedChapter = updatedChapter.copy(read = true, lastPageRead = dbChapter.last_page_read) - } else if (updatedChapter.lastPageRead == 0L && dbChapter.last_page_read != 0L) { - updatedChapter = updatedChapter.copy(lastPageRead = dbChapter.last_page_read) - } - if (!updatedChapter.bookmark && dbChapter.bookmark) { - updatedChapter = updatedChapter.copy(bookmark = true) - } - } - - updatedChapter.copy(mangaId = manga.id) - } - - val newChapters = processed.groupBy { it.id > 0 } - newChapters[true]?.let { updateKnownChapters(it) } - newChapters[false]?.let { insertChapters(it) } - } - - /** - * Returns manga - * - * @return [Manga], null if not found - */ - internal suspend fun getMangaFromDatabase(url: String, source: Long): Mangas? { - return handler.awaitOneOrNull { mangasQueries.getMangaByUrlAndSource(url, source) } - } - - /** - * Inserts manga and returns id - * - * @return id of [Manga], null if not found - */ - private suspend fun insertManga(manga: Manga): Long { - return handler.awaitOneExecutable(true) { - mangasQueries.insert( - source = manga.source, - url = manga.url, - artist = manga.artist, - author = manga.author, - description = manga.description, - genre = manga.genre, - title = manga.title, - status = manga.status, - thumbnailUrl = manga.thumbnailUrl, - favorite = manga.favorite, - lastUpdate = manga.lastUpdate, - nextUpdate = 0L, - calculateInterval = 0L, - initialized = manga.initialized, - viewerFlags = manga.viewerFlags, - chapterFlags = manga.chapterFlags, - coverLastModified = manga.coverLastModified, - dateAdded = manga.dateAdded, - updateStrategy = manga.updateStrategy, - ) - mangasQueries.selectLastInsertedRowId() - } - } - - suspend fun updateManga(manga: Manga): Long { - handler.await(true) { - mangasQueries.update( - source = manga.source, - url = manga.url, - artist = manga.artist, - author = manga.author, - description = manga.description, - genre = manga.genre?.joinToString(separator = ", "), - title = manga.title, - status = manga.status, - thumbnailUrl = manga.thumbnailUrl, - favorite = manga.favorite, - lastUpdate = manga.lastUpdate, - nextUpdate = null, - calculateInterval = null, - initialized = manga.initialized, - viewer = manga.viewerFlags, - chapterFlags = manga.chapterFlags, - coverLastModified = manga.coverLastModified, - dateAdded = manga.dateAdded, - mangaId = manga.id, - updateStrategy = manga.updateStrategy.let(UpdateStrategyColumnAdapter::encode), - ) - } - return manga.id - } - - /** - * Inserts list of chapters - */ - private suspend fun insertChapters(chapters: List) { - handler.await(true) { - chapters.forEach { chapter -> - chaptersQueries.insert( - chapter.mangaId, - chapter.url, - chapter.name, - chapter.scanlator, - chapter.read, - chapter.bookmark, - chapter.lastPageRead, - chapter.chapterNumber, - chapter.sourceOrder, - chapter.dateFetch, - chapter.dateUpload, - ) - } - } - } - - /** - * Updates a list of chapters with known database ids - */ - private suspend fun updateKnownChapters(chapters: List) { - handler.await(true) { - chapters.forEach { chapter -> - chaptersQueries.update( - mangaId = null, - url = null, - name = null, - scanlator = null, - read = chapter.read, - bookmark = chapter.bookmark, - lastPageRead = chapter.lastPageRead, - chapterNumber = null, - sourceOrder = null, - dateFetch = null, - dateUpload = null, - chapterId = chapter.id, - ) - } - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt index 2cd4bbc4a..c912be3f9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.backup import android.content.Context import android.net.Uri +import eu.kanade.domain.chapter.model.copyFrom import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.models.BackupCategory @@ -16,6 +17,7 @@ import eu.kanade.tachiyomi.data.backup.models.IntPreferenceValue import eu.kanade.tachiyomi.data.backup.models.LongPreferenceValue import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue +import eu.kanade.tachiyomi.source.model.copyFrom import eu.kanade.tachiyomi.source.sourcePreferences import eu.kanade.tachiyomi.util.BackupUtil import eu.kanade.tachiyomi.util.system.createFileInCacheDir @@ -23,7 +25,14 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.isActive import tachiyomi.core.preference.AndroidPreferenceStore import tachiyomi.core.preference.PreferenceStore +import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Manga_sync +import tachiyomi.data.Mangas +import tachiyomi.data.UpdateStrategyColumnAdapter +import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.chapter.model.Chapter +import tachiyomi.domain.history.model.HistoryUpdate +import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.track.model.Track @@ -34,20 +43,24 @@ import java.text.SimpleDateFormat import java.time.ZonedDateTime import java.util.Date import java.util.Locale +import kotlin.math.max class BackupRestorer( private val context: Context, private val notifier: BackupNotifier, ) { + + private val handler: DatabaseHandler = Injekt.get() private val updateManga: UpdateManga = Injekt.get() + private val getCategories: GetCategories = Injekt.get() private val fetchInterval: FetchInterval = Injekt.get() + private val preferenceStore: PreferenceStore = Injekt.get() + private val libraryPreferences: LibraryPreferences = Injekt.get() private var now = ZonedDateTime.now() private var currentFetchWindow = fetchInterval.getWindow(now) - private var backupManager = BackupManager(context) - private var restoreAmount = 0 private var restoreProgress = 0 @@ -102,7 +115,7 @@ class BackupRestorer( private suspend fun performRestore(uri: Uri, sync: Boolean): Boolean { val backup = BackupUtil.decodeBackup(context, uri) - restoreAmount = backup.backupManga.size + 1 // +1 for categories + restoreAmount = backup.backupManga.size + 3 // +3 for categories, app prefs, source prefs // Restore categories if (backup.backupCategories.isNotEmpty()) { @@ -134,7 +147,38 @@ class BackupRestorer( } private suspend fun restoreCategories(backupCategories: List) { - backupManager.restoreCategories(backupCategories) + // Get categories from file and from db + val dbCategories = getCategories.await() + + val categories = backupCategories.map { + var category = it.getCategory() + var found = false + for (dbCategory in dbCategories) { + // If the category is already in the db, assign the id to the file's category + // and do nothing + if (category.name == dbCategory.name) { + category = category.copy(id = dbCategory.id) + found = true + break + } + } + if (!found) { + // Let the db assign the id + val id = handler.awaitOneExecutable { + categoriesQueries.insert(category.name, category.order, category.flags) + categoriesQueries.selectLastInsertedRowId() + } + category = category.copy(id = id) + } + + category + } + + libraryPreferences.categorizedDisplaySettings().set( + (dbCategories + categories) + .distinctBy { it.flags } + .size > 1, + ) restoreProgress += 1 showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories), context.getString(R.string.restoring_backup)) @@ -149,14 +193,14 @@ class BackupRestorer( val tracks = backupManga.getTrackingImpl() try { - val dbManga = backupManager.getMangaFromDatabase(manga.url, manga.source) + val dbManga = getMangaFromDatabase(manga.url, manga.source) val restoredManga = if (dbManga == null) { // Manga not in database restoreExistingManga(manga, chapters, categories, history, tracks, backupCategories) } else { // Manga in database // Copy information from manga already in database - val updatedManga = backupManager.restoreExistingManga(manga, dbManga) + val updatedManga = restoreExistingManga(manga, dbManga) // Fetch rest of manga information restoreNewManga(updatedManga, chapters, categories, history, tracks, backupCategories) } @@ -174,6 +218,50 @@ class BackupRestorer( } } + /** + * Returns manga + * + * @return [Manga], null if not found + */ + private suspend fun getMangaFromDatabase(url: String, source: Long): Mangas? { + return handler.awaitOneOrNull { mangasQueries.getMangaByUrlAndSource(url, source) } + } + + private suspend fun restoreExistingManga(manga: Manga, dbManga: Mangas): Manga { + var updatedManga = manga.copy(id = dbManga._id) + updatedManga = updatedManga.copyFrom(dbManga) + updateManga(updatedManga) + return updatedManga + } + + private suspend fun updateManga(manga: Manga): Long { + handler.await(true) { + mangasQueries.update( + source = manga.source, + url = manga.url, + artist = manga.artist, + author = manga.author, + description = manga.description, + genre = manga.genre?.joinToString(separator = ", "), + title = manga.title, + status = manga.status, + thumbnailUrl = manga.thumbnailUrl, + favorite = manga.favorite, + lastUpdate = manga.lastUpdate, + nextUpdate = null, + calculateInterval = null, + initialized = manga.initialized, + viewer = manga.viewerFlags, + chapterFlags = manga.chapterFlags, + coverLastModified = manga.coverLastModified, + dateAdded = manga.dateAdded, + mangaId = manga.id, + updateStrategy = manga.updateStrategy.let(UpdateStrategyColumnAdapter::encode), + ) + } + return manga.id + } + /** * Fetches manga information * @@ -189,12 +277,131 @@ class BackupRestorer( tracks: List, backupCategories: List, ): Manga { - val fetchedManga = backupManager.restoreNewManga(manga) - backupManager.restoreChapters(fetchedManga, chapters) + val fetchedManga = restoreNewManga(manga) + restoreChapters(fetchedManga, chapters) restoreExtras(fetchedManga, categories, history, tracks, backupCategories) return fetchedManga } + private suspend fun restoreChapters(manga: Manga, chapters: List) { + val dbChapters = handler.awaitList { chaptersQueries.getChaptersByMangaId(manga.id) } + + val processed = chapters.map { chapter -> + var updatedChapter = chapter + val dbChapter = dbChapters.find { it.url == updatedChapter.url } + if (dbChapter != null) { + updatedChapter = updatedChapter.copy(id = dbChapter._id) + updatedChapter = updatedChapter.copyFrom(dbChapter) + if (dbChapter.read && !updatedChapter.read) { + updatedChapter = updatedChapter.copy(read = true, lastPageRead = dbChapter.last_page_read) + } else if (updatedChapter.lastPageRead == 0L && dbChapter.last_page_read != 0L) { + updatedChapter = updatedChapter.copy(lastPageRead = dbChapter.last_page_read) + } + if (!updatedChapter.bookmark && dbChapter.bookmark) { + updatedChapter = updatedChapter.copy(bookmark = true) + } + } + + updatedChapter.copy(mangaId = manga.id) + } + + val newChapters = processed.groupBy { it.id > 0 } + newChapters[true]?.let { updateKnownChapters(it) } + newChapters[false]?.let { insertChapters(it) } + } + + /** + * Inserts list of chapters + */ + private suspend fun insertChapters(chapters: List) { + handler.await(true) { + chapters.forEach { chapter -> + chaptersQueries.insert( + chapter.mangaId, + chapter.url, + chapter.name, + chapter.scanlator, + chapter.read, + chapter.bookmark, + chapter.lastPageRead, + chapter.chapterNumber, + chapter.sourceOrder, + chapter.dateFetch, + chapter.dateUpload, + ) + } + } + } + + /** + * Updates a list of chapters with known database ids + */ + private suspend fun updateKnownChapters(chapters: List) { + handler.await(true) { + chapters.forEach { chapter -> + chaptersQueries.update( + mangaId = null, + url = null, + name = null, + scanlator = null, + read = chapter.read, + bookmark = chapter.bookmark, + lastPageRead = chapter.lastPageRead, + chapterNumber = null, + sourceOrder = null, + dateFetch = null, + dateUpload = null, + chapterId = chapter.id, + ) + } + } + } + + /** + * Fetches manga information + * + * @param manga manga that needs updating + * @return Updated manga info. + */ + private suspend fun restoreNewManga(manga: Manga): Manga { + return manga.copy( + initialized = manga.description != null, + id = insertManga(manga), + ) + } + + /** + * Inserts manga and returns id + * + * @return id of [Manga], null if not found + */ + private suspend fun insertManga(manga: Manga): Long { + return handler.awaitOneExecutable(true) { + mangasQueries.insert( + source = manga.source, + url = manga.url, + artist = manga.artist, + author = manga.author, + description = manga.description, + genre = manga.genre, + title = manga.title, + status = manga.status, + thumbnailUrl = manga.thumbnailUrl, + favorite = manga.favorite, + lastUpdate = manga.lastUpdate, + nextUpdate = 0L, + calculateInterval = 0L, + initialized = manga.initialized, + viewerFlags = manga.viewerFlags, + chapterFlags = manga.chapterFlags, + coverLastModified = manga.coverLastModified, + dateAdded = manga.dateAdded, + updateStrategy = manga.updateStrategy, + ) + mangasQueries.selectLastInsertedRowId() + } + } + private suspend fun restoreNewManga( backupManga: Manga, chapters: List, @@ -203,19 +410,187 @@ class BackupRestorer( tracks: List, backupCategories: List, ): Manga { - backupManager.restoreChapters(backupManga, chapters) + restoreChapters(backupManga, chapters) restoreExtras(backupManga, categories, history, tracks, backupCategories) return backupManga } private suspend fun restoreExtras(manga: Manga, categories: List, history: List, tracks: List, backupCategories: List) { - backupManager.restoreCategories(manga, categories, backupCategories) - backupManager.restoreHistory(history) - backupManager.restoreTracking(manga, tracks) + restoreCategories(manga, categories, backupCategories) + restoreHistory(history) + restoreTracking(manga, tracks) + } + + /** + * Restores the categories a manga is in. + * + * @param manga the manga whose categories have to be restored. + * @param categories the categories to restore. + */ + private suspend fun restoreCategories(manga: Manga, categories: List, backupCategories: List) { + val dbCategories = getCategories.await() + val mangaCategoriesToUpdate = mutableListOf>() + + categories.forEach { backupCategoryOrder -> + backupCategories.firstOrNull { + it.order == backupCategoryOrder.toLong() + }?.let { backupCategory -> + dbCategories.firstOrNull { dbCategory -> + dbCategory.name == backupCategory.name + }?.let { dbCategory -> + mangaCategoriesToUpdate.add(Pair(manga.id, dbCategory.id)) + } + } + } + + // Update database + if (mangaCategoriesToUpdate.isNotEmpty()) { + handler.await(true) { + mangas_categoriesQueries.deleteMangaCategoryByMangaId(manga.id) + mangaCategoriesToUpdate.forEach { (mangaId, categoryId) -> + mangas_categoriesQueries.insert(mangaId, categoryId) + } + } + } + } + + /** + * Restore history from Json + * + * @param history list containing history to be restored + */ + private suspend fun restoreHistory(history: List) { + // List containing history to be updated + val toUpdate = mutableListOf() + for ((url, lastRead, readDuration) in history) { + var dbHistory = handler.awaitOneOrNull { historyQueries.getHistoryByChapterUrl(url) } + // Check if history already in database and update + if (dbHistory != null) { + dbHistory = dbHistory.copy( + last_read = Date(max(lastRead, dbHistory.last_read?.time ?: 0L)), + time_read = max(readDuration, dbHistory.time_read) - dbHistory.time_read, + ) + toUpdate.add( + HistoryUpdate( + chapterId = dbHistory.chapter_id, + readAt = dbHistory.last_read!!, + sessionReadDuration = dbHistory.time_read, + ), + ) + } else { + // If not in database create + handler + .awaitOneOrNull { chaptersQueries.getChapterByUrl(url) } + ?.let { + toUpdate.add( + HistoryUpdate( + chapterId = it._id, + readAt = Date(lastRead), + sessionReadDuration = readDuration, + ), + ) + } + } + } + handler.await(true) { + toUpdate.forEach { payload -> + historyQueries.upsert( + payload.chapterId, + payload.readAt, + payload.sessionReadDuration, + ) + } + } + } + + /** + * Restores the sync of a manga. + * + * @param manga the manga whose sync have to be restored. + * @param tracks the track list to restore. + */ + private suspend fun restoreTracking(manga: Manga, tracks: List) { + // Get tracks from database + val dbTracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id) } + val toUpdate = mutableListOf() + val toInsert = mutableListOf() + + tracks + // Fix foreign keys with the current manga id + .map { it.copy(mangaId = manga.id) } + .forEach { track -> + var isInDatabase = false + for (dbTrack in dbTracks) { + if (track.syncId == dbTrack.sync_id) { + // The sync is already in the db, only update its fields + var temp = dbTrack + if (track.remoteId != dbTrack.remote_id) { + temp = temp.copy(remote_id = track.remoteId) + } + if (track.libraryId != dbTrack.library_id) { + temp = temp.copy(library_id = track.libraryId) + } + temp = temp.copy(last_chapter_read = max(dbTrack.last_chapter_read, track.lastChapterRead)) + isInDatabase = true + toUpdate.add(temp) + break + } + } + if (!isInDatabase) { + // Insert new sync. Let the db assign the id + toInsert.add(track.copy(id = 0)) + } + } + + // Update database + if (toUpdate.isNotEmpty()) { + handler.await(true) { + toUpdate.forEach { track -> + manga_syncQueries.update( + track.manga_id, + track.sync_id, + track.remote_id, + track.library_id, + track.title, + track.last_chapter_read, + track.total_chapters, + track.status, + track.score, + track.remote_url, + track.start_date, + track.finish_date, + track._id, + ) + } + } + } + if (toInsert.isNotEmpty()) { + handler.await(true) { + toInsert.forEach { track -> + manga_syncQueries.insert( + track.mangaId, + track.syncId, + track.remoteId, + track.libraryId, + track.title, + track.lastChapterRead, + track.totalChapters, + track.status, + track.score, + track.remoteUrl, + track.startDate, + track.finishDate, + ) + } + } + } } private fun restoreAppPreferences(preferences: List) { restorePreferences(preferences, preferenceStore) + + restoreProgress += 1 + showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.app_settings), context.getString(R.string.restoring_backup)) } private fun restoreSourcePreferences(preferences: List) { @@ -223,6 +598,9 @@ class BackupRestorer( val sourcePrefs = AndroidPreferenceStore(context, sourcePreferences(it.sourceKey)) restorePreferences(it.prefs, sourcePrefs) } + + restoreProgress += 1 + showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.source_settings), context.getString(R.string.restoring_backup)) } private fun restorePreferences( diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/BackupUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/BackupUtil.kt index 0abd22f13..e67d7cd2f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/BackupUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/BackupUtil.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.util import android.content.Context import android.net.Uri -import eu.kanade.tachiyomi.data.backup.BackupManager +import eu.kanade.tachiyomi.data.backup.BackupCreator import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.backup.models.BackupSerializer import okio.buffer @@ -14,7 +14,7 @@ object BackupUtil { * Decode a potentially-gzipped backup. */ fun decodeBackup(context: Context, uri: Uri): Backup { - val backupManager = BackupManager(context) + val backupCreator = BackupCreator(context) val backupStringSource = context.contentResolver.openInputStream(uri)!!.source().buffer() @@ -27,6 +27,6 @@ object BackupUtil { backupStringSource }.use { it.readByteArray() } - return backupManager.parser.decodeFromByteArray(BackupSerializer, backupString) + return backupCreator.parser.decodeFromByteArray(BackupSerializer, backupString) } } From 94cba9324c872b1f0caa3f4d385266f190a9b114 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 8 Oct 2023 16:23:57 -0400 Subject: [PATCH 54/59] Remove beta webtoon viewer split page This had a bunch of issues around split pages not showing up properly so things end up appearing to be missing while reading. It'd be more worthwhile redoing the reader viewers than trying to get this to work properly. It'd be better to just enable the split pages on download instead. Closes #8433 --- .../settings/screen/SettingsReaderScreen.kt | 7 ---- .../reader/settings/ReadingModePage.kt | 8 ---- .../java/eu/kanade/tachiyomi/Migrations.kt | 8 ---- .../data/backup/BackupFileValidator.kt | 5 ++- .../tachiyomi/data/backup/BackupRestoreJob.kt | 7 ++-- .../tachiyomi/ui/reader/ReaderViewModel.kt | 5 +-- .../tachiyomi/ui/reader/model/StencilPage.kt | 16 ------- .../ui/reader/setting/ReaderPreferences.kt | 4 -- .../reader/viewer/webtoon/WebtoonAdapter.kt | 23 ---------- .../ui/reader/viewer/webtoon/WebtoonConfig.kt | 14 ------- .../viewer/webtoon/WebtoonPageHolder.kt | 34 --------------- .../ui/reader/viewer/webtoon/WebtoonViewer.kt | 23 ---------- .../tachiyomi/core/util/system/ImageUtil.kt | 42 ------------------- i18n/src/main/res/values/strings.xml | 1 - 14 files changed, 9 insertions(+), 188 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/StencilPage.kt diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt index bb73b89ec..ef35ea38b 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt @@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType -import eu.kanade.tachiyomi.util.system.isReleaseBuildType import tachiyomi.presentation.core.util.collectAsState import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -305,12 +304,6 @@ object SettingsReaderScreen : SearchableSettings { subtitle = stringResource(R.string.pref_dual_page_invert_summary), enabled = dualPageSplit, ), - Preference.PreferenceItem.SwitchPreference( - pref = readerPreferences.longStripSplitWebtoon(), - title = stringResource(R.string.pref_long_strip_split), - subtitle = stringResource(R.string.split_tall_images_summary), - enabled = !isReleaseBuildType, // TODO: Show in release build when the feature is stable - ), Preference.PreferenceItem.SwitchPreference( pref = readerPreferences.webtoonDoubleTapZoomEnabled(), title = stringResource(R.string.pref_double_tap_zoom), diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt index 874a053cd..07d6cb49a 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt @@ -16,7 +16,6 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer -import eu.kanade.tachiyomi.util.system.isReleaseBuildType import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.HeadingItem import tachiyomi.presentation.core.components.SettingsChipRow @@ -185,13 +184,6 @@ private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenM ) } - if (!isReleaseBuildType) { - CheckboxItem( - label = stringResource(R.string.pref_long_strip_split), - pref = screenModel.preferences.longStripSplitWebtoon(), - ) - } - CheckboxItem( label = stringResource(R.string.pref_double_tap_zoom), pref = screenModel.preferences.webtoonDoubleTapZoomEnabled(), diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index f341e26a6..bbdcaa6ea 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.util.system.DeviceUtil -import eu.kanade.tachiyomi.util.system.isReleaseBuildType import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.workManager import tachiyomi.core.preference.Preference @@ -363,13 +362,6 @@ object Migrations { if (oldVersion < 100) { BackupCreateJob.setupTask(context) } - if (oldVersion < 102) { - // This was accidentally visible from the reader settings sheet, but should always - // be disabled in release builds. - if (isReleaseBuildType) { - readerPreferences.longStripSplitWebtoon().set(false) - } - } if (oldVersion < 105) { val pref = libraryPreferences.autoUpdateDeviceRestrictions() if (pref.isSet() && "battery_not_low" in pref.get()) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt index ea8f3c9ea..8450ab367 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt @@ -58,5 +58,8 @@ class BackupFileValidator( return Results(missingSources, missingTrackers) } - data class Results(val missingSources: List, val missingTrackers: List) + data class Results( + val missingSources: List, + val missingTrackers: List, + ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreJob.kt index 4f1c45bc2..170ddb80f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreJob.kt @@ -26,7 +26,7 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet override suspend fun doWork(): Result { val uri = inputData.getString(LOCATION_URI_KEY)?.toUri() ?: return Result.failure() - val sync = inputData.getBoolean(SYNC, false) + val sync = inputData.getBoolean(SYNC_KEY, false) try { setForeground(getForegroundInfo()) @@ -67,7 +67,7 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet fun start(context: Context, uri: Uri, sync: Boolean = false) { val inputData = workDataOf( LOCATION_URI_KEY to uri.toString(), - SYNC to sync, + SYNC_KEY to sync, ) val request = OneTimeWorkRequestBuilder() .addTag(TAG) @@ -85,5 +85,4 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet private const val TAG = "BackupRestore" private const val LOCATION_URI_KEY = "location_uri" // String - -private const val SYNC = "sync" // Boolean +private const val SYNC_KEY = "sync" // Boolean diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt index 8d16c7b80..ff098b92e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt @@ -27,7 +27,6 @@ import eu.kanade.tachiyomi.ui.reader.loader.DownloadPageLoader import eu.kanade.tachiyomi.ui.reader.model.InsertPage import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderPage -import eu.kanade.tachiyomi.ui.reader.model.StencilPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences @@ -405,8 +404,8 @@ class ReaderViewModel @JvmOverloads constructor( * [page]'s chapter is different from the currently active. */ fun onPageSelected(page: ReaderPage) { - // InsertPage and StencilPage doesn't change page progress - if (page is InsertPage || page is StencilPage) { + // InsertPage doesn't change page progress + if (page is InsertPage) { return } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/StencilPage.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/StencilPage.kt deleted file mode 100644 index c5a7ee79f..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/StencilPage.kt +++ /dev/null @@ -1,16 +0,0 @@ -package eu.kanade.tachiyomi.ui.reader.model - -import java.io.InputStream - -class StencilPage( - parent: ReaderPage, - stencilStream: () -> InputStream, -) : ReaderPage(parent.index, parent.url, parent.imageUrl) { - - override var chapter: ReaderChapter = parent.chapter - - init { - status = State.READY - stream = stencilStream - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt index 23a5beb13..a58cd9096 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt @@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.reader.setting import androidx.annotation.StringRes import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.util.system.isReleaseBuildType import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.getEnum @@ -33,9 +32,6 @@ class ReaderPreferences( fun defaultOrientationType() = preferenceStore.getInt("pref_default_orientation_type_key", OrientationType.FREE.flagValue) - // TODO: Enable in release build when the feature is stable - fun longStripSplitWebtoon() = preferenceStore.getBoolean("pref_long_strip_split_webtoon", !isReleaseBuildType) - fun webtoonDoubleTapZoomEnabled() = preferenceStore.getBoolean("pref_enable_double_tap_zoom_webtoon", true) fun imageScaleType() = preferenceStore.getInt("pref_image_scale_type_key", 1) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.kt index 87edd1da4..036f767f8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.kt @@ -7,12 +7,10 @@ import androidx.recyclerview.widget.RecyclerView import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderPage -import eu.kanade.tachiyomi.ui.reader.model.StencilPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView import eu.kanade.tachiyomi.ui.reader.viewer.calculateChapterGap import eu.kanade.tachiyomi.util.system.createReaderThemeContext -import tachiyomi.core.util.system.logcat /** * RecyclerView Adapter used by this [viewer] to where [ViewerChapters] updates are posted. @@ -27,27 +25,6 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : RecyclerView.Adapter) { - if (newStrips.isEmpty()) return - if (currentStrip is StencilPage) return - - val placeAtIndex = items.indexOf(currentStrip) + 1 - // Stop constantly adding split images - if (items.getOrNull(placeAtIndex) is StencilPage) return - - val updatedItems = items.toMutableList() - updatedItems.addAll(placeAtIndex, newStrips) - updateItems(updatedItems) - logcat { "New adapter item count is $itemCount" } - } - - fun cleanupSplitStrips() { - if (items.any { it is StencilPage }) { - val updatedItems = items.filterNot { it is StencilPage } - updateItems(updatedItems) - } - } - /** * Context that has been wrapped to use the correct theme values based on the * current app theme and reader background color diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt index b2e0045b8..a64826ab1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt @@ -32,11 +32,6 @@ class WebtoonConfig( var sidePadding = 0 private set - var longStripSplit = false - private set - - var longStripSplitChangedListener: ((Boolean) -> Unit)? = null - var doubleTapZoom = true private set @@ -67,15 +62,6 @@ class WebtoonConfig( readerPreferences.dualPageInvertWebtoon() .register({ dualPageInvert = it }, { imagePropertyChangedListener?.invoke() }) - readerPreferences.longStripSplitWebtoon() - .register( - { longStripSplit = it }, - { - imagePropertyChangedListener?.invoke() - longStripSplitChangedListener?.invoke(it) - }, - ) - readerPreferences.webtoonDoubleTapZoomEnabled() .register( { doubleTapZoom = it }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt index 749a48e33..7fa2058d6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt @@ -13,7 +13,6 @@ import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import eu.kanade.tachiyomi.databinding.ReaderErrorBinding import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.ui.reader.model.ReaderPage -import eu.kanade.tachiyomi.ui.reader.model.StencilPage import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator import eu.kanade.tachiyomi.ui.webview.WebViewActivity @@ -24,12 +23,10 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.suspendCancellableCoroutine -import logcat.LogPriority import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.system.ImageUtil -import tachiyomi.core.util.system.logcat import java.io.BufferedInputStream import java.io.InputStream @@ -221,40 +218,9 @@ class WebtoonPageHolder( } } - if (viewer.config.longStripSplit) { - if (page is StencilPage) { - return imageStream - } - val isStripSplitNeeded = ImageUtil.isStripSplitNeeded(imageStream) - if (isStripSplitNeeded) { - return onStripSplit(imageStream) - } - } - return imageStream } - private fun onStripSplit(imageStream: BufferedInputStream): InputStream { - try { - // If we have reached this point [page] and its stream shouldn't be null - val page = page!! - val stream = page.stream!! - val splitData = ImageUtil.getSplitDataForStream(imageStream).toMutableList() - val currentSplitData = splitData.removeFirst() - val newPages = splitData.map { - StencilPage(page) { ImageUtil.splitStrip(it, stream) } - } - return ImageUtil.splitStrip(currentSplitData) { imageStream } - .also { - // Running [onLongStripSplit] first results in issues with splitting - viewer.onLongStripSplit(page, newPages) - } - } catch (e: Exception) { - logcat(LogPriority.ERROR, e) { "Failed to split image" } - return imageStream - } - } - /** * Called when the page has an error. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index d7a0290f3..d85a5b04b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition import eu.kanade.tachiyomi.ui.reader.model.ReaderPage -import eu.kanade.tachiyomi.ui.reader.model.StencilPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.viewer.Viewer @@ -151,12 +150,6 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr activity.binding.navigationOverlay.setNavigation(config.navigator, showOnStart) } - config.longStripSplitChangedListener = { enabled -> - if (!enabled) { - cleanupSplitStrips() - } - } - frame.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT) frame.addView(recycler) } @@ -205,11 +198,6 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr logcat { "onPageSelected: ${page.number}/${pages.size}" } activity.onPageSelected(page) - // Skip preload on StencilPage - if (page is StencilPage) { - return - } - // Preload next chapter once we're within the last 5 pages of the current chapter val inPreloadRange = pages.size - page.number < 5 if (inPreloadRange && allowPreload && page.chapter == adapter.currentChapter) { @@ -359,15 +347,4 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr min(position + 3, adapter.itemCount - 1), ) } - - fun onLongStripSplit(currentStrip: Any?, newStrips: List) { - activity.runOnUiThread { - // Need to insert on UI thread else images will go blank - adapter.onLongStripSplit(currentStrip, newStrips) - } - } - - private fun cleanupSplitStrips() { - adapter.cleanupSplitStrips() - } } diff --git a/core/src/main/java/tachiyomi/core/util/system/ImageUtil.kt b/core/src/main/java/tachiyomi/core/util/system/ImageUtil.kt index fdfff4603..62a0d347a 100644 --- a/core/src/main/java/tachiyomi/core/util/system/ImageUtil.kt +++ b/core/src/main/java/tachiyomi/core/util/system/ImageUtil.kt @@ -273,48 +273,6 @@ object ImageUtil { private fun splitImageName(filenamePrefix: String, index: Int) = "${filenamePrefix}__${"%03d".format(index + 1)}.jpg" - /** - * Check whether the image is a long Strip that needs splitting - * @return true if the image is not animated and it's height is greater than image width and screen height - */ - fun isStripSplitNeeded(imageStream: BufferedInputStream): Boolean { - if (isAnimatedAndSupported(imageStream)) return false - - val options = extractImageOptions(imageStream) - val imageHeightIsBiggerThanWidth = options.outHeight > options.outWidth - val imageHeightBiggerThanScreenHeight = options.outHeight > optimalImageHeight - return imageHeightIsBiggerThanWidth && imageHeightBiggerThanScreenHeight - } - - /** - * Split the imageStream according to the provided splitData - */ - fun splitStrip(splitData: SplitData, streamFn: () -> InputStream): InputStream { - val bitmapRegionDecoder = getBitmapRegionDecoder(streamFn()) - ?: throw Exception("Failed to create new instance of BitmapRegionDecoder") - - logcat { - "WebtoonSplit #${splitData.index} with topOffset=${splitData.topOffset} " + - "splitHeight=${splitData.splitHeight} bottomOffset=${splitData.bottomOffset}" - } - - try { - val region = Rect(0, splitData.topOffset, splitData.splitWidth, splitData.bottomOffset) - val splitBitmap = bitmapRegionDecoder.decodeRegion(region, null) - val outputStream = ByteArrayOutputStream() - splitBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) - return ByteArrayInputStream(outputStream.toByteArray()) - } catch (e: Throwable) { - throw e - } finally { - bitmapRegionDecoder.recycle() - } - } - - fun getSplitDataForStream(imageStream: InputStream): List { - return extractImageOptions(imageStream).splitData - } - private val BitmapFactory.Options.splitData get(): List { val imageHeight = outHeight diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index ac21d13f6..612567f3f 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -329,7 +329,6 @@ If the placement of the split wide pages don\'t match reading direction Rotate wide pages to fit Flip orientation of rotated wide pages - Split tall images (BETA) Double tap to zoom Show content in cutout area Animate page transitions From 7ed99fbbd61bd6748573b1c5463f3c552de8832d Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 8 Oct 2023 16:40:17 -0400 Subject: [PATCH 55/59] Account for skipped entries when showing large updates warning Closes #6159 --- .../data/library/LibraryUpdateJob.kt | 153 ++++++++++-------- .../data/library/LibraryUpdateNotifier.kt | 6 +- i18n/src/main/res/values/strings.xml | 2 +- 3 files changed, 88 insertions(+), 73 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt index 734b5180c..651858332 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt @@ -186,7 +186,40 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet .distinctBy { it.manga.id } } + val restrictions = libraryPreferences.autoUpdateMangaRestrictions().get() + val skippedUpdates = mutableListOf>() + val fetchWindow = fetchInterval.getWindow(ZonedDateTime.now()) + mangaToUpdate = listToUpdate + .filter { + when { + it.manga.updateStrategy != UpdateStrategy.ALWAYS_UPDATE -> { + skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_always_update)) + false + } + + MANGA_NON_COMPLETED in restrictions && it.manga.status.toInt() == SManga.COMPLETED -> { + skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_completed)) + false + } + + MANGA_HAS_UNREAD in restrictions && it.unreadCount != 0L -> { + skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_caught_up)) + false + } + + MANGA_NON_READ in restrictions && it.totalChapters > 0L && !it.hasStarted -> { + skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_started)) + false + } + + MANGA_OUTSIDE_RELEASE_PERIOD in restrictions && it.manga.nextUpdate > fetchWindow.second -> { + skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_in_release_period)) + false + } + else -> true + } + } .sortedBy { it.manga.title } // Warn when excessively checking a single source @@ -197,6 +230,17 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD) { notifier.showQueueSizeWarningNotification() } + + if (skippedUpdates.isNotEmpty()) { + // TODO: surface skipped reasons to user? + logcat { + skippedUpdates + .groupBy { it.second } + .map { (reason, entries) -> "$reason: [${entries.map { it.first.title }.sorted().joinToString()}]" } + .joinToString() + } + notifier.showUpdateSkippedNotification(skippedUpdates.size) + } } /** @@ -212,10 +256,8 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet val progressCount = AtomicInteger(0) val currentlyUpdatingManga = CopyOnWriteArrayList() val newUpdates = CopyOnWriteArrayList>>() - val skippedUpdates = CopyOnWriteArrayList>() val failedUpdates = CopyOnWriteArrayList>() val hasDownloads = AtomicBoolean(false) - val restrictions = libraryPreferences.autoUpdateMangaRestrictions().get() val fetchWindow = fetchInterval.getWindow(ZonedDateTime.now()) coroutineScope { @@ -237,49 +279,30 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet progressCount, manga, ) { - when { - manga.updateStrategy != UpdateStrategy.ALWAYS_UPDATE -> - skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_always_update)) + try { + val newChapters = updateManga(manga, fetchWindow) + .sortedByDescending { it.sourceOrder } - MANGA_NON_COMPLETED in restrictions && manga.status.toInt() == SManga.COMPLETED -> - skippedUpdates.add(manga to context.getString(R.string.skipped_reason_completed)) - - MANGA_HAS_UNREAD in restrictions && libraryManga.unreadCount != 0L -> - skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_caught_up)) - - MANGA_NON_READ in restrictions && libraryManga.totalChapters > 0L && !libraryManga.hasStarted -> - skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_started)) - - MANGA_OUTSIDE_RELEASE_PERIOD in restrictions && manga.nextUpdate > fetchWindow.second -> - skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_in_release_period)) - - else -> { - try { - val newChapters = updateManga(manga, fetchWindow) - .sortedByDescending { it.sourceOrder } - - if (newChapters.isNotEmpty()) { - val categoryIds = getCategories.await(manga.id).map { it.id } - if (manga.shouldDownloadNewChapters(categoryIds, downloadPreferences)) { - downloadChapters(manga, newChapters) - hasDownloads.set(true) - } - - libraryPreferences.newUpdatesCount().getAndSet { it + newChapters.size } - - // Convert to the manga that contains new chapters - newUpdates.add(manga to newChapters.toTypedArray()) - } - } catch (e: Throwable) { - val errorMessage = when (e) { - is NoChaptersException -> context.getString(R.string.no_chapters_error) - // failedUpdates will already have the source, don't need to copy it into the message - is SourceNotInstalledException -> context.getString(R.string.loader_not_implemented_error) - else -> e.message - } - failedUpdates.add(manga to errorMessage) + if (newChapters.isNotEmpty()) { + val categoryIds = getCategories.await(manga.id).map { it.id } + if (manga.shouldDownloadNewChapters(categoryIds, downloadPreferences)) { + downloadChapters(manga, newChapters) + hasDownloads.set(true) } + + libraryPreferences.newUpdatesCount().getAndSet { it + newChapters.size } + + // Convert to the manga that contains new chapters + newUpdates.add(manga to newChapters.toTypedArray()) } + } catch (e: Throwable) { + val errorMessage = when (e) { + is NoChaptersException -> context.getString(R.string.no_chapters_error) + // failedUpdates will already have the source, don't need to copy it into the message + is SourceNotInstalledException -> context.getString(R.string.loader_not_implemented_error) + else -> e.message + } + failedUpdates.add(manga to errorMessage) } if (libraryPreferences.autoUpdateTrackers().get()) { @@ -309,16 +332,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet errorFile.getUriCompat(context), ) } - if (skippedUpdates.isNotEmpty()) { - // TODO: surface skipped reasons to user - logcat { - skippedUpdates - .groupBy { it.second } - .map { (reason, entries) -> "$reason: [${entries.map { it.first.title }.sorted().joinToString()}]" } - .joinToString() - } - notifier.showUpdateSkippedNotification(skippedUpdates.size) - } } private fun downloadChapters(manga: Manga, chapters: List) { @@ -428,29 +441,27 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet completed: AtomicInteger, manga: Manga, block: suspend () -> Unit, - ) { - coroutineScope { - ensureActive() + ) = coroutineScope { + ensureActive() - updatingManga.add(manga) - notifier.showProgressNotification( - updatingManga, - completed.get(), - mangaToUpdate.size, - ) + updatingManga.add(manga) + notifier.showProgressNotification( + updatingManga, + completed.get(), + mangaToUpdate.size, + ) - block() + block() - ensureActive() + ensureActive() - updatingManga.remove(manga) - completed.getAndIncrement() - notifier.showProgressNotification( - updatingManga, - completed.get(), - mangaToUpdate.size, - ) - } + updatingManga.remove(manga) + completed.getAndIncrement() + notifier.showProgressNotification( + updatingManga, + completed.get(), + mangaToUpdate.size, + ) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt index 299889b8c..833680ba4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt @@ -30,10 +30,14 @@ import tachiyomi.core.util.lang.launchUI import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.model.Manga import uy.kohesive.injekt.injectLazy +import java.text.NumberFormat class LibraryUpdateNotifier(private val context: Context) { private val preferences: SecurityPreferences by injectLazy() + private val percentFormatter = NumberFormat.getPercentInstance().apply { + maximumFractionDigits = 0 + } /** * Pending intent of action that cancels the library update @@ -78,7 +82,7 @@ class LibraryUpdateNotifier(private val context: Context) { } else { val updatingText = manga.joinToString("\n") { it.title.chop(40) } progressNotificationBuilder - .setContentTitle(context.getString(R.string.notification_updating, current, total)) + .setContentTitle(context.getString(R.string.notification_updating_progress, percentFormatter.format(current.toFloat() / total))) .setStyle(NotificationCompat.BigTextStyle().bigText(updatingText)) } diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 612567f3f..bb2918baa 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -837,7 +837,7 @@ Checking for new chapters - Updating library… (%1$d/%2$d) + Updating library… (%s) Large updates harm sources and may lead to slower updates and also increased battery usage. Tap to learn more. New chapters found From 8568d5d6c3ceae0084a350906b330f23dab571e1 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 8 Oct 2023 17:04:02 -0400 Subject: [PATCH 56/59] Always save pages/covers in subfolders Ensures that pages and covers are grouped together. --- .../more/settings/screen/SettingsReaderScreen.kt | 5 ----- .../java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt | 10 ++-------- .../kanade/tachiyomi/ui/manga/MangaCoverScreenModel.kt | 4 ++-- .../eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt | 7 ++----- .../tachiyomi/ui/reader/setting/ReaderPreferences.kt | 2 -- i18n/src/main/res/values/strings.xml | 2 -- 6 files changed, 6 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt index ef35ea38b..e4ac76681 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt @@ -342,11 +342,6 @@ object SettingsReaderScreen : SearchableSettings { pref = readerPreferences.readWithLongTap(), title = stringResource(R.string.pref_read_with_long_tap), ), - Preference.PreferenceItem.SwitchPreference( - pref = readerPreferences.folderPerManga(), - title = stringResource(R.string.pref_create_folder_per_manga), - subtitle = stringResource(R.string.pref_create_folder_per_manga_summary), - ), ), ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt index 7086f1023..783d8bdae 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt @@ -166,19 +166,12 @@ sealed class Image( } sealed interface Location { - data class Pictures private constructor(val relativePath: String) : Location { - companion object { - fun create(relativePath: String = ""): Pictures { - return Pictures(relativePath) - } - } - } + data class Pictures(val relativePath: String) : Location data object Cache : Location fun directory(context: Context): File { return when (this) { - Cache -> context.cacheImageDir is Pictures -> { val file = File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), @@ -192,6 +185,7 @@ sealed interface Location { } file } + Cache -> context.cacheImageDir } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaCoverScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaCoverScreenModel.kt index ffb6553c4..784a99aa2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaCoverScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaCoverScreenModel.kt @@ -102,8 +102,8 @@ class MangaCoverScreenModel( imageSaver.save( Image.Cover( bitmap = bitmap, - name = manga.title, - location = if (temp) Location.Cache else Location.Pictures.create(), + name = "cover", + location = if (temp) Location.Cache else Location.Pictures(manga.title), ), ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt index ff098b92e..55be5fd61 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt @@ -740,17 +740,14 @@ class ReaderViewModel @JvmOverloads constructor( val filename = generateFilename(manga, page) - // Pictures directory. - val relativePath = if (readerPreferences.folderPerManga().get()) DiskUtil.buildValidFilename(manga.title) else "" - - // Copy file in background. + // Copy file in background viewModelScope.launchNonCancellable { try { val uri = imageSaver.save( image = Image.Page( inputStream = page.stream!!, name = filename, - location = Location.Pictures.create(relativePath), + location = Location.Pictures(DiskUtil.buildValidFilename(manga.title)), ), ) withUIContext { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt index a58cd9096..faf75d0ba 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt @@ -54,8 +54,6 @@ class ReaderPreferences( fun readerHideThreshold() = preferenceStore.getEnum("reader_hide_threshold", ReaderHideThreshold.LOW) - fun folderPerManga() = preferenceStore.getBoolean("create_folder_per_manga", false) - fun skipRead() = preferenceStore.getBoolean("skip_read", false) fun skipFiltered() = preferenceStore.getBoolean("skip_filtered", true) diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index bb2918baa..41d216db5 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -363,8 +363,6 @@ Both Actions Show actions on long tap - Save pages into separate folders - Creates folders according to entries\' title Background color White Gray From 77ebc362f6d6b765ed2de6d1be18a969df4ca1f3 Mon Sep 17 00:00:00 2001 From: Pauline <87093166+Hipp0x@users.noreply.github.com> Date: Mon, 9 Oct 2023 00:55:15 +0200 Subject: [PATCH 57/59] Add button to reorder categories alphabetically (#9369) Closes #6459 Co-authored-by: arkon --- .../presentation/category/CategoryScreen.kt | 39 +++++++++++++++++-- .../category/components/CategoryDialogs.kt | 29 ++++++++++++++ .../tachiyomi/ui/category/CategoryScreen.kt | 8 ++++ .../ui/category/CategoryScreenModel.kt | 10 +++++ .../category/interactor/ReorderCategory.kt | 21 ++++++++++ i18n/src/main/res/values/strings.xml | 2 + 6 files changed, 106 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt b/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt index f7d699164..3e3364d79 100644 --- a/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt @@ -7,13 +7,22 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ArrowBack +import androidx.compose.material.icons.outlined.SortByAlpha +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import eu.kanade.presentation.category.components.CategoryFloatingActionButton import eu.kanade.presentation.category.components.CategoryListItem import eu.kanade.presentation.components.AppBar +import eu.kanade.presentation.components.AppBarActions import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.category.CategoryScreenState import tachiyomi.domain.category.model.Category @@ -27,6 +36,7 @@ import tachiyomi.presentation.core.util.plus fun CategoryScreen( state: CategoryScreenState.Success, onClickCreate: () -> Unit, + onClickSortAlphabetically: () -> Unit, onClickRename: (Category) -> Unit, onClickDelete: (Category) -> Unit, onClickMoveUp: (Category) -> Unit, @@ -36,9 +46,32 @@ fun CategoryScreen( val lazyListState = rememberLazyListState() Scaffold( topBar = { scrollBehavior -> - AppBar( - title = stringResource(R.string.action_edit_categories), - navigateUp = navigateUp, + TopAppBar( + title = { + Text( + text = stringResource(R.string.action_edit_categories), + modifier = Modifier.padding(start = 8.dp), + ) + }, + navigationIcon = { + IconButton(onClick = navigateUp) { + Icon( + imageVector = Icons.Outlined.ArrowBack, + contentDescription = stringResource(R.string.abc_action_bar_up_description), + ) + } + }, + actions = { + AppBarActions( + listOf( + AppBar.Action( + title = stringResource(R.string.action_sort), + icon = Icons.Outlined.SortByAlpha, + onClick = onClickSortAlphabetically, + ), + ), + ) + }, scrollBehavior = scrollBehavior, ) }, diff --git a/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt b/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt index 0e99d26c1..ad30e4e2d 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt @@ -180,6 +180,35 @@ fun CategoryDeleteDialog( ) } +@Composable +fun CategorySortAlphabeticallyDialog( + onDismissRequest: () -> Unit, + onSort: () -> Unit, +) { + AlertDialog( + onDismissRequest = onDismissRequest, + confirmButton = { + TextButton(onClick = { + onSort() + onDismissRequest() + }) { + Text(text = stringResource(R.string.action_ok)) + } + }, + dismissButton = { + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(R.string.action_cancel)) + } + }, + title = { + Text(text = stringResource(R.string.action_sort_category)) + }, + text = { + Text(text = stringResource(R.string.sort_category_confirmation)) + }, + ) +} + @Composable fun ChangeCategoryDialog( initialSelection: List>, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt index 77628a415..bc9fbd4a5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt @@ -12,6 +12,7 @@ import eu.kanade.presentation.category.CategoryScreen import eu.kanade.presentation.category.components.CategoryCreateDialog import eu.kanade.presentation.category.components.CategoryDeleteDialog import eu.kanade.presentation.category.components.CategoryRenameDialog +import eu.kanade.presentation.category.components.CategorySortAlphabeticallyDialog import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.util.system.toast import kotlinx.coroutines.flow.collectLatest @@ -37,6 +38,7 @@ class CategoryScreen : Screen() { CategoryScreen( state = successState, onClickCreate = { screenModel.showDialog(CategoryDialog.Create) }, + onClickSortAlphabetically = { screenModel.showDialog(CategoryDialog.SortAlphabetically) }, onClickRename = { screenModel.showDialog(CategoryDialog.Rename(it)) }, onClickDelete = { screenModel.showDialog(CategoryDialog.Delete(it)) }, onClickMoveUp = screenModel::moveUp, @@ -68,6 +70,12 @@ class CategoryScreen : Screen() { category = dialog.category, ) } + is CategoryDialog.SortAlphabetically -> { + CategorySortAlphabeticallyDialog( + onDismissRequest = screenModel::dismissDialog, + onSort = { screenModel.sortAlphabetically() }, + ) + } } LaunchedEffect(Unit) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt index 45fbdcb4a..3a04a3475 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt @@ -61,6 +61,15 @@ class CategoryScreenModel( } } + fun sortAlphabetically() { + coroutineScope.launch { + when (reorderCategory.sortAlphabetically()) { + is ReorderCategory.Result.InternalError -> _events.send(CategoryEvent.InternalError) + else -> {} + } + } + } + fun moveUp(category: Category) { coroutineScope.launch { when (reorderCategory.moveUp(category)) { @@ -109,6 +118,7 @@ class CategoryScreenModel( sealed interface CategoryDialog { data object Create : CategoryDialog + data object SortAlphabetically : CategoryDialog data class Rename(val category: Category) : CategoryDialog data class Delete(val category: Category) : CategoryDialog } diff --git a/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt b/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt index b29cfd093..7561f52c8 100644 --- a/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt +++ b/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt @@ -55,6 +55,27 @@ class ReorderCategory( } } + suspend fun sortAlphabetically() = withNonCancellableContext { + mutex.withLock { + val updates = categoryRepository.getAll() + .sortedBy { category -> category.name } + .mapIndexed { index, category -> + CategoryUpdate( + id = category.id, + order = index.toLong(), + ) + } + + try { + categoryRepository.updatePartial(updates) + Result.Success + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + Result.InternalError(e) + } + } + } + sealed interface Result { data object Success : Result data object Unchanged : Result diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 41d216db5..aca17a122 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -91,6 +91,8 @@ Set categories Do you wish to delete the category \"%s\"? Delete category + Sort categories + Would you like to sort the categories alphabetically? Edit cover View chapters Pause From b7d282235dd233aac3bbdba3c9cfe7cac877b2e1 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 8 Oct 2023 19:19:04 -0400 Subject: [PATCH 58/59] Remove duplicated logic for binding enhanced trackers --- .../domain/track/interactor/AddTracks.kt | 44 +++++++++---------- .../kanade/tachiyomi/ui/history/HistoryTab.kt | 2 +- .../tachiyomi/ui/manga/MangaScreenModel.kt | 22 ++-------- 3 files changed, 25 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt b/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt index 5a56889fb..45340e44a 100644 --- a/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt +++ b/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt @@ -17,31 +17,29 @@ class AddTracks( private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack, ) { - suspend fun bindEnhancedTracks(manga: Manga, source: Source) { - withNonCancellableContext { - getTracks.await(manga.id) - .filterIsInstance() - .filter { it.accept(source) } - .forEach { service -> - try { - service.match(manga)?.let { track -> - track.manga_id = manga.id - (service as Tracker).bind(track) - insertTrack.await(track.toDomainTrack()!!) + suspend fun bindEnhancedTracks(manga: Manga, source: Source) = withNonCancellableContext { + getTracks.await(manga.id) + .filterIsInstance() + .filter { it.accept(source) } + .forEach { service -> + try { + service.match(manga)?.let { track -> + track.manga_id = manga.id + (service as Tracker).bind(track) + insertTrack.await(track.toDomainTrack()!!) - syncChapterProgressWithTrack.await( - manga.id, - track.toDomainTrack()!!, - service, - ) - } - } catch (e: Exception) { - logcat( - LogPriority.WARN, - e, - ) { "Could not match manga: ${manga.title} with service $service" } + syncChapterProgressWithTrack.await( + manga.id, + track.toDomainTrack()!!, + service, + ) } + } catch (e: Exception) { + logcat( + LogPriority.WARN, + e, + ) { "Could not match manga: ${manga.title} with service $service" } } - } + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryTab.kt index a6a08ff8c..2306216a7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryTab.kt @@ -116,7 +116,7 @@ object HistoryTab : Tab { } } - suspend fun openChapter(context: Context, chapter: Chapter?) { + private suspend fun openChapter(context: Context, chapter: Chapter?) { if (chapter != null) { val intent = ReaderActivity.newIntent(context, chapter.mangaId, chapter.id) context.startActivity(intent) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index 9e94a2605..8d1bace7d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -15,6 +15,7 @@ import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.model.downloadedFilter import eu.kanade.domain.manga.model.toSManga +import eu.kanade.domain.track.interactor.AddTracks import eu.kanade.domain.ui.UiPreferences import eu.kanade.presentation.manga.DownloadAction import eu.kanade.presentation.manga.components.ChapterDownloadAction @@ -24,7 +25,6 @@ import eu.kanade.tachiyomi.data.download.DownloadCache import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.track.EnhancedTracker -import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.network.HttpException import eu.kanade.tachiyomi.source.Source @@ -97,6 +97,7 @@ class MangaScreenModel( private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(), private val getCategories: GetCategories = Injekt.get(), private val getTracks: GetTracks = Injekt.get(), + private val addTracks: AddTracks = Injekt.get(), private val setMangaCategories: SetMangaCategories = Injekt.get(), private val mangaRepository: MangaRepository = Injekt.get(), val snackbarHostState: SnackbarHostState = SnackbarHostState(), @@ -315,24 +316,7 @@ class MangaScreenModel( } // Finally match with enhanced tracking when available - val source = state.source - state.trackItems - .map { it.tracker } - .filterIsInstance() - .filter { it.accept(source) } - .forEach { service -> - launchIO { - try { - service.match(manga)?.let { track -> - (service as Tracker).register(track, mangaId) - } - } catch (e: Exception) { - logcat(LogPriority.WARN, e) { - "Could not match manga: ${manga.title} with service $service" - } - } - } - } + addTracks.bindEnhancedTracks(manga, state.source) } } } From 79b37df647049df90921cae1fabdca2312404784 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 8 Oct 2023 22:27:06 -0400 Subject: [PATCH 59/59] Automatically convert details.json to ComicInfo.xml for local series Originally contributed as #9603 I ended up coming back to this since it seems like a reasonable way to migrate users in the short-medium term. We'll remove this in a later release. Co-authored-by: Shamicen --- .../core/metadata/comicinfo/ComicInfo.kt | 25 ++++++++++- .../tachiyomi/source/local/LocalSource.kt | 42 ++++++++++++------- .../source/local/image/LocalCoverManager.kt | 2 +- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/core-metadata/src/main/java/tachiyomi/core/metadata/comicinfo/ComicInfo.kt b/core-metadata/src/main/java/tachiyomi/core/metadata/comicinfo/ComicInfo.kt index 06cce7ccc..681b4819b 100644 --- a/core-metadata/src/main/java/tachiyomi/core/metadata/comicinfo/ComicInfo.kt +++ b/core-metadata/src/main/java/tachiyomi/core/metadata/comicinfo/ComicInfo.kt @@ -8,6 +8,27 @@ import nl.adaptivity.xmlutil.serialization.XmlValue const val COMIC_INFO_FILE = "ComicInfo.xml" +fun SManga.getComicInfo() = ComicInfo( + series = ComicInfo.Series(title), + summary = description?.let { ComicInfo.Summary(it) }, + writer = author?.let { ComicInfo.Writer(it) }, + penciller = artist?.let { ComicInfo.Penciller(it) }, + genre = genre?.let { ComicInfo.Genre(it) }, + publishingStatus = ComicInfo.PublishingStatusTachiyomi( + ComicInfoPublishingStatus.toComicInfoValue(status.toLong()), + ), + title = null, + number = null, + web = null, + translator = null, + inker = null, + colorist = null, + letterer = null, + coverArtist = null, + tags = null, + categories = null, +) + fun SManga.copyFromComicInfo(comicInfo: ComicInfo) { comicInfo.series?.let { title = it.value } comicInfo.writer?.let { author = it.value } @@ -39,6 +60,8 @@ fun SManga.copyFromComicInfo(comicInfo: ComicInfo) { status = ComicInfoPublishingStatus.toSMangaValue(comicInfo.publishingStatus?.value) } +// https://anansi-project.github.io/docs/comicinfo/schemas/v2.0 +@Suppress("UNUSED") @Serializable @XmlSerialName("ComicInfo", "", "") data class ComicInfo( @@ -59,12 +82,10 @@ data class ComicInfo( val publishingStatus: PublishingStatusTachiyomi?, val categories: CategoriesTachiyomi?, ) { - @Suppress("UNUSED") @XmlElement(false) @XmlSerialName("xmlns:xsd", "", "") val xmlSchema: String = "http://www.w3.org/2001/XMLSchema" - @Suppress("UNUSED") @XmlElement(false) @XmlSerialName("xmlns:xsi", "", "") val xmlSchemaInstance: String = "http://www.w3.org/2001/XMLSchema-instance" diff --git a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt index b74dcbb2d..636d205f2 100644 --- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt +++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt @@ -1,6 +1,7 @@ package tachiyomi.source.local import android.content.Context +import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.UnmeteredSource @@ -10,7 +11,6 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder import eu.kanade.tachiyomi.util.storage.EpubFile -import kotlinx.coroutines.runBlocking import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream import logcat.LogPriority @@ -19,6 +19,7 @@ import nl.adaptivity.xmlutil.serialization.XML import tachiyomi.core.metadata.comicinfo.COMIC_INFO_FILE import tachiyomi.core.metadata.comicinfo.ComicInfo import tachiyomi.core.metadata.comicinfo.copyFromComicInfo +import tachiyomi.core.metadata.comicinfo.getComicInfo import tachiyomi.core.metadata.tachiyomi.MangaDetails import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.system.ImageUtil @@ -122,22 +123,20 @@ actual class LocalSource( // Fetch chapters of all the manga mangas.forEach { manga -> - runBlocking { - val chapters = getChapterList(manga) - if (chapters.isNotEmpty()) { - val chapter = chapters.last() - val format = getFormat(chapter) + val chapters = getChapterList(manga) + if (chapters.isNotEmpty()) { + val chapter = chapters.last() + val format = getFormat(chapter) - if (format is Format.Epub) { - EpubFile(format.file).use { epub -> - epub.fillMangaMetadata(manga) - } + if (format is Format.Epub) { + EpubFile(format.file).use { epub -> + epub.fillMangaMetadata(manga) } + } - // Copy the cover from the first chapter found if not available - if (manga.thumbnail_url == null) { - updateCover(chapter, manga) - } + // Copy the cover from the first chapter found if not available + if (manga.thumbnail_url == null) { + updateCover(chapter, manga) } } } @@ -153,6 +152,7 @@ actual class LocalSource( // Augment manga details based on metadata files try { + val mangaDir = fileSystem.getMangaDirectory(manga.url) val mangaDirFiles = fileSystem.getFilesInMangaDirectory(manga.url).toList() val comicInfoFile = mangaDirFiles @@ -169,7 +169,8 @@ actual class LocalSource( setMangaDetailsFromComicInfoFile(comicInfoFile.inputStream(), manga) } - // TODO: automatically convert these to ComicInfo.xml + // Old custom JSON format + // TODO: remove support for this entirely after a while legacyJsonDetailsFile != null -> { json.decodeFromStream(legacyJsonDetailsFile.inputStream()).run { title?.let { manga.title = it } @@ -179,6 +180,16 @@ actual class LocalSource( genre?.let { manga.genre = it.joinToString() } status?.let { manga.status = it } } + // Replace with ComicInfo.xml file + val comicInfo = manga.getComicInfo() + UniFile.fromFile(mangaDir) + ?.createFile(COMIC_INFO_FILE) + ?.openOutputStream() + ?.use { + val comicInfoString = xml.encodeToString(ComicInfo.serializer(), comicInfo) + it.write(comicInfoString.toByteArray()) + legacyJsonDetailsFile.delete() + } } // Copy ComicInfo.xml from chapter archive to top level if found @@ -187,7 +198,6 @@ actual class LocalSource( .filter(Archive::isSupported) .toList() - val mangaDir = fileSystem.getMangaDirectory(manga.url) val folderPath = mangaDir?.absolutePath val copiedFile = copyComicInfoFileFromArchive(chapterArchives, folderPath) diff --git a/source-local/src/androidMain/kotlin/tachiyomi/source/local/image/LocalCoverManager.kt b/source-local/src/androidMain/kotlin/tachiyomi/source/local/image/LocalCoverManager.kt index e5aaf5dd7..7683756e3 100644 --- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/image/LocalCoverManager.kt +++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/image/LocalCoverManager.kt @@ -18,7 +18,7 @@ actual class LocalCoverManager( actual fun find(mangaUrl: String): File? { return fileSystem.getFilesInMangaDirectory(mangaUrl) - // Get all file whose names start with 'cover' + // Get all file whose names start with "cover" .filter { it.isFile && it.nameWithoutExtension.equals("cover", ignoreCase = true) } // Get the first actual image .firstOrNull {