From 092d930175e7a9a6e1bb73f8d97948903db06d67 Mon Sep 17 00:00:00 2001 From: arkon Date: Tue, 24 Oct 2023 21:58:53 -0400 Subject: [PATCH 01/66] Update default user agent string --- .../main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 cba50e99c..b552f4423 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt @@ -19,7 +19,7 @@ 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", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0", ) } } From 0a0b6861190b087776e60e8e20b5cb21d7e2a855 Mon Sep 17 00:00:00 2001 From: arkon Date: Tue, 24 Oct 2023 22:16:03 -0400 Subject: [PATCH 02/66] Add Compose previews for reading and orientation mode dialogs --- .../reader/OrientationModeSelectDialog.kt | 58 +++++++++++++------ .../reader/ReadingModeSelectDialog.kt | 58 +++++++++++++------ 2 files changed, 82 insertions(+), 34 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 0fbe079a9..a143634ab 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt @@ -15,13 +15,13 @@ 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.presentation.theme.TachiyomiTheme 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.SettingsIconGrid import tachiyomi.presentation.core.components.material.IconToggleButton - -private val orientationTypeOptions = OrientationType.entries.map { it.stringRes to it } +import tachiyomi.presentation.core.util.ThemePreviews @Composable fun OrientationModeSelectDialog( @@ -33,22 +33,46 @@ fun OrientationModeSelectDialog( val orientationType = remember(manga) { OrientationType.fromPreference(manga?.orientationType?.toInt()) } 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() - }, - modifier = Modifier.fillMaxWidth(), - imageVector = ImageVector.vectorResource(mode.iconRes), - title = stringResource(stringRes), - ) - } + DialogContent( + orientationType = orientationType, + onChangeOrientation = { + screenModel.onChangeOrientation(it) + onChange(it.stringRes) + onDismissRequest() + }, + ) + } +} + +@Composable +private fun DialogContent( + orientationType: OrientationType, + onChangeOrientation: (OrientationType) -> Unit, +) { + Box(modifier = Modifier.padding(vertical = 16.dp)) { + SettingsIconGrid(R.string.rotation_type) { + items(OrientationType.entries) { mode -> + IconToggleButton( + checked = mode == orientationType, + onCheckedChange = { + onChangeOrientation(mode) + }, + modifier = Modifier.fillMaxWidth(), + imageVector = ImageVector.vectorResource(mode.iconRes), + title = stringResource(mode.stringRes), + ) } } } } + +@ThemePreviews +@Composable +private fun DialogContentPreview() { + TachiyomiTheme { + DialogContent( + orientationType = OrientationType.DEFAULT, + onChangeOrientation = {}, + ) + } +} 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 cb11d9950..a2089c7f5 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt @@ -15,14 +15,14 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import eu.kanade.domain.manga.model.readingModeType import eu.kanade.presentation.components.AdaptiveSheet +import eu.kanade.presentation.theme.TachiyomiTheme 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.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 } +import tachiyomi.presentation.core.util.ThemePreviews @Composable fun ReadingModeSelectDialog( @@ -34,22 +34,46 @@ fun ReadingModeSelectDialog( val readingMode = remember(manga) { ReadingModeType.fromPreference(manga?.readingModeType?.toInt()) } 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() - }, - modifier = Modifier.fillMaxWidth(), - imageVector = ImageVector.vectorResource(mode.iconRes), - title = stringResource(stringRes), - ) - } + DialogContent( + readingMode = readingMode, + onChangeReadingMode = { + screenModel.onChangeReadingMode(it) + onChange(it.stringRes) + onDismissRequest() + }, + ) + } +} + +@Composable +private fun DialogContent( + readingMode: ReadingModeType, + onChangeReadingMode: (ReadingModeType) -> Unit, +) { + Box(modifier = Modifier.padding(vertical = MaterialTheme.padding.medium)) { + SettingsIconGrid(R.string.pref_category_reading_mode) { + items(ReadingModeType.entries) { mode -> + IconToggleButton( + checked = mode == readingMode, + onCheckedChange = { + onChangeReadingMode(mode) + }, + modifier = Modifier.fillMaxWidth(), + imageVector = ImageVector.vectorResource(mode.iconRes), + title = stringResource(mode.stringRes), + ) } } } } + +@ThemePreviews +@Composable +private fun DialogContentPreview() { + TachiyomiTheme { + DialogContent( + readingMode = ReadingModeType.DEFAULT, + onChangeReadingMode = {}, + ) + } +} From d9c0b1ce7d1739da3945622f2d18b171a471fc2e Mon Sep 17 00:00:00 2001 From: arkon Date: Tue, 24 Oct 2023 22:21:17 -0400 Subject: [PATCH 03/66] Migrate reader low brightness overlay to Compose --- .../presentation/reader/BrightnessOverlay.kt | 26 +++++++++++++++++++ .../reader/appbars/ReaderAppBars.kt | 6 ++--- .../tachiyomi/ui/reader/ReaderActivity.kt | 15 +++++------ .../tachiyomi/ui/reader/ReaderViewModel.kt | 5 ++++ app/src/main/res/layout/reader_activity.xml | 6 ----- 5 files changed, 39 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt diff --git a/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt b/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt new file mode 100644 index 000000000..df927a4ba --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt @@ -0,0 +1,26 @@ +package eu.kanade.presentation.reader + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import kotlin.math.abs + +@Composable +fun BrightnessOverlay( + value: Int, +) { + if (value >= 0) return + + Canvas( + modifier = Modifier + .fillMaxSize() + .graphicsLayer { + alpha = abs(value) / 100f + } + ) { + drawRect(Color.Black) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt index 1683b2028..55a28e437 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -9,10 +9,8 @@ import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.systemBars -import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Bookmark import androidx.compose.material.icons.outlined.BookmarkBorder @@ -70,7 +68,7 @@ fun ReaderAppBars( .copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f) val appBarModifier = if (fullscreen) { - Modifier.windowInsetsPadding(WindowInsets.systemBars) + Modifier.systemBarsPadding() } else { Modifier } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 6d58736e3..9ac903fc3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -42,6 +42,7 @@ import com.google.android.material.elevation.SurfaceColors import com.google.android.material.transition.platform.MaterialContainerTransform import dev.chrisbanes.insetter.applyInsetter import eu.kanade.domain.base.BasePreferences +import eu.kanade.presentation.reader.BrightnessOverlay import eu.kanade.presentation.reader.OrientationModeSelectDialog import eu.kanade.presentation.reader.PageIndicatorText import eu.kanade.presentation.reader.ReaderPageActionsDialog @@ -377,6 +378,10 @@ class ReaderActivity : BaseActivity() { onClickSettings = viewModel::openSettingsDialog, ) + BrightnessOverlay( + value = state.brightnessOverlayValue, + ) + val onDismissRequest = viewModel::closeDialog when (state.dialog) { is ReaderViewModel.Dialog.Loading -> { @@ -903,17 +908,9 @@ class ReaderActivity : BaseActivity() { } else -> WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE } - window.attributes = window.attributes.apply { screenBrightness = readerBrightness } - // Set black overlay visibility. - if (value < 0) { - binding.brightnessOverlay.isVisible = true - val alpha = (abs(value) * 2.56).toInt() - binding.brightnessOverlay.setBackgroundColor(Color.argb(alpha, 0, 0, 0)) - } else { - binding.brightnessOverlay.isVisible = false - } + viewModel.setBrightnessOverlayValue(value) } /** 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 c16c5a362..555bdef3a 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 @@ -736,6 +736,10 @@ class ReaderViewModel @JvmOverloads constructor( mutableState.update { it.copy(dialog = null) } } + fun setBrightnessOverlayValue(value: Int) { + mutableState.update { it.copy(brightnessOverlayValue = value) } + } + /** * Saves the image of the selected page on the pictures directory and notifies the UI of the result. * There's also a notification to allow sharing the image somewhere else or deleting it. @@ -894,6 +898,7 @@ class ReaderViewModel @JvmOverloads constructor( val viewer: Viewer? = null, val dialog: Dialog? = null, val menuVisible: Boolean = false, + val brightnessOverlayValue: Int = 0, ) { val currentChapter: ReaderChapter? get() = viewerChapters?.currChapter diff --git a/app/src/main/res/layout/reader_activity.xml b/app/src/main/res/layout/reader_activity.xml index 2401432ff..da843c09f 100644 --- a/app/src/main/res/layout/reader_activity.xml +++ b/app/src/main/res/layout/reader_activity.xml @@ -35,12 +35,6 @@ android:focusable="false" android:visibility="gone" /> - - Date: Wed, 25 Oct 2023 09:18:59 -0400 Subject: [PATCH 04/66] Avoid opening blobs as webpages Fixes #10060 --- .../eu/kanade/presentation/webview/WebViewScreenContent.kt | 6 ++++++ 1 file changed, 6 insertions(+) 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 354fd2e29..50d387cf1 100644 --- a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt +++ b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt @@ -100,6 +100,12 @@ fun WebViewScreenContent( request: WebResourceRequest?, ): Boolean { request?.let { + // Don't attempt to open blobs as webpages + if (it.url.toString().startsWith("blob:http")) { + return false + } + + // Continue with request, but with custom headers view?.loadUrl(it.url.toString(), headers) } return super.shouldOverrideUrlLoading(view, request) From 8057f067b964835897a2365cee0307cfdc1472f6 Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 25 Oct 2023 09:21:04 -0400 Subject: [PATCH 05/66] Handle reader app bar insets in Compose --- .../eu/kanade/presentation/reader/BrightnessOverlay.kt | 2 +- .../eu/kanade/presentation/reader/appbars/ReaderAppBars.kt | 5 +++-- .../java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt | 7 ------- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt b/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt index df927a4ba..144b8ea27 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt @@ -19,7 +19,7 @@ fun BrightnessOverlay( .fillMaxSize() .graphicsLayer { alpha = abs(value) / 100f - } + }, ) { drawRect(Color.Black) } diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt index 55a28e437..e044d5ccf 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -67,7 +67,7 @@ fun ReaderAppBars( .surfaceColorAtElevation(3.dp) .copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f) - val appBarModifier = if (fullscreen) { + val modifierWithInsetsPadding = if (fullscreen) { Modifier.systemBarsPadding() } else { Modifier @@ -89,7 +89,7 @@ fun ReaderAppBars( ), ) { AppBar( - modifier = appBarModifier + modifier = modifierWithInsetsPadding .clickable(onClick = onClickTopAppBar), backgroundColor = backgroundColor, title = mangaTitle, @@ -135,6 +135,7 @@ fun ReaderAppBars( ), ) { Column( + modifier = modifierWithInsetsPadding, verticalArrangement = Arrangement.spacedBy(8.dp), ) { ChapterNavigator( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 9ac903fc3..1b8784d1a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -92,7 +92,6 @@ import tachiyomi.domain.manga.model.Manga import tachiyomi.presentation.core.util.collectAsState import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import kotlin.math.abs class ReaderActivity : BaseActivity() { @@ -299,12 +298,6 @@ class ReaderActivity : BaseActivity() { * Initializes the reader menu. It sets up click listeners and the initial visibility. */ private fun initializeMenu() { - binding.dialogRoot.applyInsetter { - type(navigationBars = true) { - margin(vertical = true, horizontal = true) - } - } - binding.pageNumber.setComposeContent { val state by viewModel.state.collectAsState() val showPageNumber by viewModel.readerPreferences.showPageNumber().collectAsState() From 91712daee8733eab5df69bf6abc066d067854837 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 16 Jul 2023 15:44:36 -0400 Subject: [PATCH 06/66] Use consistent extension icon URLs Better caching between versions. (cherry picked from commit 30f845139d76762798e2cdec7804a38806c3eeca) --- .../eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt index d83d53bfa..9e2ad2eb5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt @@ -117,7 +117,7 @@ internal class ExtensionGithubApi { hasChangelog = it.hasChangelog == 1, sources = it.sources?.toExtensionSources() ?: emptyList(), apkName = it.apk, - iconUrl = "${getUrlPrefix()}icon/${it.apk.replace(".apk", ".png")}", + iconUrl = "${getUrlPrefix()}icon/${it.pkg}.png", ) } } From f77ade7dda60e0e72e704d53d57f16ecae61e40c Mon Sep 17 00:00:00 2001 From: Soitora Date: Sun, 17 Sep 2023 18:08:12 +0200 Subject: [PATCH 07/66] 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 (cherry picked from commit 9e04f14a7be6e3fa069b90a9577798d661fe2c9a) --- .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 5bea25988..13b54a0a2 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 7c703b17d31b01c5893cbcc75a328fc0f9dfe137 Mon Sep 17 00:00:00 2001 From: Vlasov Roman Date: Thu, 19 Oct 2023 09:49:45 +0700 Subject: [PATCH 08/66] Change Shikimori domain from ".me" to ".one" (#10027) (cherry picked from commit 8f3681d79f1624a092e5c356c9459897f4220c29) --- .../eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5340f8562..2d16a10dc 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 @@ -158,7 +158,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter private const val clientId = "1aaf4cf232372708e98b5abc813d795b539c5a916dbbfe9ac61bf02a360832cc" private const val clientSecret = "229942c742dd4cde803125d17d64501d91c0b12e14cb1e5120184d77d67024c0" - private const val baseUrl = "https://shikimori.me" + private const val baseUrl = "https://shikimori.one" private const val apiUrl = "$baseUrl/api" private const val oauthUrl = "$baseUrl/oauth/token" private const val loginUrl = "$baseUrl/oauth/authorize" From f8834ee764e3ff448efe2ebc76e64cbb2f2a6f41 Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 25 Oct 2023 09:18:59 -0400 Subject: [PATCH 09/66] Avoid opening blobs as webpages Fixes #10060 (cherry picked from commit 548f7f415a28529522f5aef0d53546e8bc68957e) --- .../eu/kanade/presentation/webview/WebViewScreenContent.kt | 6 ++++++ 1 file changed, 6 insertions(+) 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 b496a6a05..a5b18ca3e 100644 --- a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt +++ b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt @@ -124,6 +124,12 @@ fun WebViewScreenContent( request: WebResourceRequest?, ): Boolean { request?.let { + // Don't attempt to open blobs as webpages + if (it.url.toString().startsWith("blob:http")) { + return false + } + + // Continue with request, but with custom headers view?.loadUrl(it.url.toString(), headers) } return super.shouldOverrideUrlLoading(view, request) From 28028c789c7035c598ad90d695b749bb92750a67 Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 25 Oct 2023 11:54:41 -0400 Subject: [PATCH 10/66] Update default user agent string --- .../main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt | 2 +- .../main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 1fdb1d81a..82c475ec1 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,6 @@ class NetworkPreferences( } fun defaultUserAgent(): Preference { - return preferenceStore.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0") + return preferenceStore.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0") } } 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 beef906d7..a9f700e34 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 @@ -12,7 +12,7 @@ import tachiyomi.core.util.system.logcat object WebViewUtil { const val SPOOF_PACKAGE_NAME = "org.chromium.chrome" - const val MINIMUM_WEBVIEW_VERSION = 108 + const val MINIMUM_WEBVIEW_VERSION = 114 fun supportsWebView(context: Context): Boolean { try { From 94448faf972d22cf58d78472d0af5715ef990a28 Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 25 Oct 2023 11:58:00 -0400 Subject: [PATCH 11/66] Update website links --- app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt | 2 +- .../kanade/presentation/more/settings/screen/AboutScreen.kt | 2 +- .../more/settings/screen/SettingsTrackingScreen.kt | 2 +- .../eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt | 4 ++-- .../eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt | 2 +- .../eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt | 2 +- app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.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 +- 11 files changed, 12 insertions(+), 12 deletions(-) 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 b463318d6..39872f5e6 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#how-do-i-update-from-the-f-droid-builds") }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/AboutScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/AboutScreen.kt index 931603ef2..2f4819fcc 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/AboutScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/AboutScreen.kt @@ -118,7 +118,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/contribute#translation") }, ) } 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 582b6efa0..b16f88d99 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/tachiyomi/data/library/LibraryUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt index 9a989fdb6..ebbf1314d 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 @@ -340,11 +340,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/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/library#why-is-global-update-skipping-entries" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt index 021bfdddb..d8be18417 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt @@ -604,4 +604,4 @@ class LibraryUpdateService( } private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60 -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/" 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 53aacd4cf..650a94a9c 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 @@ -138,7 +138,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#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/source/LocalSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt index 03ad7c22a..244142acb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt @@ -384,7 +384,7 @@ 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-source/" private const val DEFAULT_COVER_NAME = "cover.jpg" private val LATEST_THRESHOLD = TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS) 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 1cdf9c16d..fb594cde1 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/browse/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 6b3c7a916..cf41a3488 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 6aa817b9d..c059f98fe 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 @@ -156,7 +156,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" From c8d68590db31f5a14dc9a5a1c457f75acd10d59c Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 25 Oct 2023 12:04:09 -0400 Subject: [PATCH 12/66] Release v0.14.7 --- .github/ISSUE_TEMPLATE.md | 2 +- .github/ISSUE_TEMPLATE/report_issue.yml | 4 ++-- .github/ISSUE_TEMPLATE/request_feature.yml | 2 +- app/build.gradle.kts | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 15794612e..f036b12f7 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -3,7 +3,7 @@ I acknowledge that: - I have updated: - - To the latest version of the app (stable is v0.14.6) + - To the latest version of the app (stable is v0.14.7) - All extensions - I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/ - If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions diff --git a/.github/ISSUE_TEMPLATE/report_issue.yml b/.github/ISSUE_TEMPLATE/report_issue.yml index 368f41ded..cdc8d2239 100644 --- a/.github/ISSUE_TEMPLATE/report_issue.yml +++ b/.github/ISSUE_TEMPLATE/report_issue.yml @@ -53,7 +53,7 @@ body: label: Tachiyomi version description: You can find your Tachiyomi version in **More → About**. placeholder: | - Example: "0.14.6" + Example: "0.14.7" validations: required: true @@ -98,7 +98,7 @@ body: required: true - label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/). required: true - - label: I have updated the app to version **[0.14.6](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**. + - label: I have updated the app to version **[0.14.7](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**. required: true - label: I have updated all installed extensions. required: true diff --git a/.github/ISSUE_TEMPLATE/request_feature.yml b/.github/ISSUE_TEMPLATE/request_feature.yml index af59d3565..b5f8296c0 100644 --- a/.github/ISSUE_TEMPLATE/request_feature.yml +++ b/.github/ISSUE_TEMPLATE/request_feature.yml @@ -33,7 +33,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 updated the app to version **[0.14.6](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**. + - label: I have updated the app to version **[0.14.7](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**. required: true - label: I will fill out all of the requested information in this form. required: true diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 95fe09172..6340093b4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,8 +22,8 @@ android { defaultConfig { applicationId = "eu.kanade.tachiyomi" - versionCode = 101 - versionName = "0.14.6" + versionCode = 102 + versionName = "0.14.7" buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"") From 0bdd3f79d4d14318ba8110748c6d39484c6d446b Mon Sep 17 00:00:00 2001 From: Seishirou101 <57241064+Seishirou101@users.noreply.github.com> Date: Wed, 25 Oct 2023 21:13:46 -0500 Subject: [PATCH 13/66] Add info about problematic extensions to debug logs (#10059) * add ext info to crashlog * add unofficial to crashlog too * update to have header include unofficial too * after ktlintFormat * Clean up debug info output --------- Co-authored-by: arkon --- .../eu/kanade/tachiyomi/util/CrashLogUtil.kt | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) 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 505ec3cf9..7f39823e7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.util import android.content.Context import android.os.Build import eu.kanade.tachiyomi.BuildConfig +import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.system.WebViewUtil import eu.kanade.tachiyomi.util.system.createFileInCacheDir @@ -10,14 +11,22 @@ import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast import tachiyomi.core.util.lang.withNonCancellableContext import tachiyomi.core.util.lang.withUIContext +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get -class CrashLogUtil(private val context: Context) { +class CrashLogUtil( + private val context: Context, + private val extensionManager: ExtensionManager = Injekt.get(), +) { suspend fun dumpLogs() = withNonCancellableContext { try { val file = context.createFileInCacheDir("tachiyomi_crash_logs.txt") + + file.appendText(getDebugInfo() + "\n\n") + getExtensionsInfo()?.let { file.appendText("$it\n\n") } + Runtime.getRuntime().exec("logcat *:E -d -f ${file.absolutePath}").waitFor() - file.appendText(getDebugInfo()) val uri = file.getUriCompat(context) context.startActivity(uri.toShareIntent(context, "text/plain")) @@ -29,14 +38,38 @@ class CrashLogUtil(private val context: Context) { fun getDebugInfo(): String { return """ App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR}, ${BuildConfig.COMMIT_SHA}, ${BuildConfig.VERSION_CODE}, ${BuildConfig.BUILD_TIME}) - Android version: ${Build.VERSION.RELEASE} (SDK ${Build.VERSION.SDK_INT}) - Android build ID: ${Build.DISPLAY} + Android version: ${Build.VERSION.RELEASE} (SDK ${Build.VERSION.SDK_INT}; build ${Build.DISPLAY}) Device brand: ${Build.BRAND} Device manufacturer: ${Build.MANUFACTURER} - Device name: ${Build.DEVICE} + Device name: ${Build.DEVICE} (${Build.PRODUCT}) Device model: ${Build.MODEL} - Device product name: ${Build.PRODUCT} WebView: ${WebViewUtil.getVersion(context)} """.trimIndent() } + + private fun getExtensionsInfo(): String? { + val availableExtensions = extensionManager.availableExtensionsFlow.value.associateBy { it.pkgName } + + val extensionInfoList = extensionManager.installedExtensionsFlow.value + .sortedBy { it.name } + .mapNotNull { + val availableExtension = availableExtensions[it.pkgName] + val hasUpdate = (availableExtension?.versionCode ?: 0) > it.versionCode + + if (!hasUpdate && !it.isObsolete && !it.isUnofficial) return@mapNotNull null + + """ + - ${it.name} + Installed: ${it.versionName} / Available: ${availableExtension?.versionName ?: "?"} + Obsolete: ${it.isObsolete} / Unofficial: ${it.isUnofficial} + """.trimIndent() + } + + return if (extensionInfoList.isNotEmpty()) { + (listOf("Problematic extensions:") + extensionInfoList) + .joinToString("\n") + } else { + null + } + } } From 9ecec5d468629f647f7c6370c78983d5bcf5b670 Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 26 Oct 2023 08:35:51 -0400 Subject: [PATCH 14/66] Set saved image date modified value to current time Fixes #10070 --- app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt | 2 ++ 1 file changed, 2 insertions(+) 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 783d8bdae..60446da02 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 @@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.File import java.io.InputStream +import java.util.Date class ImageSaver( val context: Context, @@ -77,6 +78,7 @@ class ImageSaver( 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.DATE_MODIFIED to Date().time * 1000, ) val picture = findUriOrDefault(relativePath, filename) { From 17b90d2491c63a43dba147e93d4e6d0ea54984fd Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Thu, 26 Oct 2023 22:30:40 +0600 Subject: [PATCH 15/66] Yeet app update download progress notification on complete (#10071) --- .../java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt index b7a0f9517..c1f973d2d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt @@ -127,6 +127,7 @@ class AppUpdateService : Service() { response.close() throw Exception("Unsuccessful response") } + notifier.cancel() notifier.promptInstall(apkFile.getUriCompat(this)) } catch (e: Exception) { val shouldCancel = e is CancellationException || From d7d7a6d2fc7e4fda286a4a01fe31afe46309376e Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 26 Oct 2023 13:06:20 -0400 Subject: [PATCH 16/66] Revert Compose update Fixes #10069 --- .../eu/kanade/presentation/browse/BrowseSourceScreen.kt | 6 +++--- .../kanade/presentation/browse/ExtensionDetailsScreen.kt | 4 ++-- .../presentation/browse/components/BrowseSourceToolbar.kt | 4 ++-- .../browse/components/GlobalSearchResultItems.kt | 3 +-- .../presentation/browse/components/GlobalSearchToolbar.kt | 2 +- .../presentation/category/components/CategoryListItem.kt | 3 +-- .../main/java/eu/kanade/presentation/components/AppBar.kt | 7 +++++-- .../eu/kanade/presentation/components/DropdownMenu.kt | 8 ++++++-- .../java/eu/kanade/presentation/components/EmptyScreen.kt | 3 +-- .../eu/kanade/presentation/components/TabbedDialog.kt | 4 ++-- .../eu/kanade/presentation/components/TabbedScreen.kt | 4 ++-- .../kanade/presentation/library/components/LibraryTabs.kt | 4 ++-- .../manga/components/ChapterDownloadIndicator.kt | 2 +- .../manga/components/MangaBottomActionMenu.kt | 3 +-- .../main/java/eu/kanade/presentation/more/MoreScreen.kt | 6 ++---- .../java/eu/kanade/presentation/more/NewUpdateScreen.kt | 3 +-- .../more/settings/screen/SettingsMainScreen.kt | 3 +-- .../more/settings/screen/SettingsTrackingScreen.kt | 3 +-- .../java/eu/kanade/presentation/track/TrackerSearch.kt | 3 +-- .../kanade/presentation/webview/WebViewScreenContent.kt | 8 +++----- .../ui/browse/migration/sources/MigrateSourceTab.kt | 3 +-- .../kanade/tachiyomi/ui/download/DownloadQueueScreen.kt | 3 +-- .../java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt | 3 +-- gradle/compose.versions.toml | 4 ++-- 24 files changed, 44 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt index f399bb5b8..833e4bf79 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt @@ -4,7 +4,7 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.HelpOutline +import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material.icons.outlined.Public import androidx.compose.material.icons.outlined.Refresh import androidx.compose.material3.SnackbarDuration @@ -79,7 +79,7 @@ fun BrowseSourceContent( listOf( EmptyScreenAction( stringResId = R.string.local_source_help_guide, - icon = Icons.AutoMirrored.Outlined.HelpOutline, + icon = Icons.Outlined.HelpOutline, onClick = onLocalSourceHelpClick, ), ) @@ -97,7 +97,7 @@ fun BrowseSourceContent( ), EmptyScreenAction( stringResId = R.string.label_help, - icon = Icons.AutoMirrored.Outlined.HelpOutline, + icon = Icons.Outlined.HelpOutline, onClick = onHelpClick, ), ) diff --git a/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt index 715e93b52..b319f9fdc 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt @@ -16,7 +16,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.HelpOutline +import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material.icons.outlined.History import androidx.compose.material.icons.outlined.Settings import androidx.compose.material3.AlertDialog @@ -92,7 +92,7 @@ fun ExtensionDetailsScreen( add( AppBar.Action( title = stringResource(R.string.action_faq_and_guides), - icon = Icons.AutoMirrored.Outlined.HelpOutline, + icon = Icons.Outlined.HelpOutline, onClick = onClickReadme, ), ) diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt index 4afd8c9a2..ccea144a2 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt @@ -1,7 +1,7 @@ package eu.kanade.presentation.browse.components import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ViewList +import androidx.compose.material.icons.filled.ViewList import androidx.compose.material.icons.filled.ViewModule import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarScrollBehavior @@ -56,7 +56,7 @@ fun BrowseSourceToolbar( actions = listOfNotNull( AppBar.Action( title = stringResource(R.string.action_display_mode), - icon = if (displayMode == LibraryDisplayMode.List) Icons.AutoMirrored.Filled.ViewList else Icons.Filled.ViewModule, + icon = if (displayMode == LibraryDisplayMode.List) Icons.Filled.ViewList else Icons.Filled.ViewModule, onClick = { selectingDisplayMode = true }, ), if (isLocalSource) { diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchResultItems.kt b/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchResultItems.kt index 4661c304c..1270c011b 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchResultItems.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchResultItems.kt @@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.ArrowForward import androidx.compose.material.icons.outlined.ArrowForward import androidx.compose.material.icons.outlined.Error import androidx.compose.material3.CircularProgressIndicator @@ -55,7 +54,7 @@ fun GlobalSearchResultItem( Text(text = subtitle) } IconButton(onClick = onClick) { - Icon(imageVector = Icons.AutoMirrored.Outlined.ArrowForward, contentDescription = null) + Icon(imageVector = Icons.Outlined.ArrowForward, contentDescription = null) } } content() diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchToolbar.kt b/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchToolbar.kt index 965894af8..6f108abba 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/GlobalSearchToolbar.kt @@ -58,7 +58,7 @@ fun GlobalSearchToolbar( ) if (progress in 1.. Unit, ) { Column { - PrimaryScrollableTabRow( + ScrollableTabRow( selectedTabIndex = pagerState.currentPage, edgePadding = 0.dp, indicator = { TabIndicator(it[pagerState.currentPage], pagerState.currentPageOffsetFraction) }, diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/ChapterDownloadIndicator.kt b/app/src/main/java/eu/kanade/presentation/manga/components/ChapterDownloadIndicator.kt index ce9fb64bf..1e8931740 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/ChapterDownloadIndicator.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/ChapterDownloadIndicator.kt @@ -148,7 +148,7 @@ private fun DownloadingIndicator( MaterialTheme.colorScheme.background } CircularProgressIndicator( - progress = { animatedProgress }, + progress = animatedProgress, modifier = IndicatorModifier, color = strokeColor, strokeWidth = IndicatorSize / 2, 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 6f31d5a1f..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 @@ -23,7 +23,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.shape.ZeroCornerSize import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.Label import androidx.compose.material.icons.outlined.BookmarkAdd import androidx.compose.material.icons.outlined.BookmarkRemove import androidx.compose.material.icons.outlined.Delete @@ -259,7 +258,7 @@ fun LibraryBottomActionMenu( ) { Button( title = stringResource(R.string.action_move_category), - icon = Icons.AutoMirrored.Outlined.Label, + icon = Icons.Outlined.Label, toConfirm = confirm[0], onLongClick = { onLongClickItem(0) }, onClick = onChangeCategoryClicked, 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 5a685ccaf..5ef863c51 100644 --- a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt @@ -9,8 +9,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.HelpOutline -import androidx.compose.material.icons.automirrored.outlined.Label import androidx.compose.material.icons.outlined.CloudOff import androidx.compose.material.icons.outlined.GetApp import androidx.compose.material.icons.outlined.HelpOutline @@ -130,7 +128,7 @@ fun MoreScreen( item { TextPreferenceWidget( title = stringResource(R.string.categories), - icon = Icons.AutoMirrored.Outlined.Label, + icon = Icons.Outlined.Label, onPreferenceClick = onClickCategories, ) } @@ -168,7 +166,7 @@ fun MoreScreen( item { TextPreferenceWidget( title = stringResource(R.string.label_help), - icon = Icons.AutoMirrored.Outlined.HelpOutline, + icon = Icons.Outlined.HelpOutline, onPreferenceClick = { uriHandler.openUri(Constants.URL_HELP) }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt b/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt index c1480a965..5e1c4d7ce 100644 --- a/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.OpenInNew import androidx.compose.material.icons.filled.OpenInNew import androidx.compose.material.icons.outlined.NewReleases import androidx.compose.material3.Icon @@ -61,7 +60,7 @@ fun NewUpdateScreen( ) { Text(text = stringResource(R.string.update_check_open)) Spacer(modifier = Modifier.width(MaterialTheme.padding.tiny)) - Icon(imageVector = Icons.AutoMirrored.Outlined.OpenInNew, contentDescription = null) + Icon(imageVector = Icons.Default.OpenInNew, contentDescription = null) } } } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt index 93e33b28b..5f9c4e9b5 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.ChromeReaderMode import androidx.compose.material.icons.outlined.ChromeReaderMode import androidx.compose.material.icons.outlined.Code import androidx.compose.material.icons.outlined.CollectionsBookmark @@ -187,7 +186,7 @@ object SettingsMainScreen : Screen() { Item( titleRes = R.string.pref_category_reader, subtitleRes = R.string.pref_reader_summary, - icon = Icons.AutoMirrored.Outlined.ChromeReaderMode, + icon = Icons.Outlined.ChromeReaderMode, screen = SettingsReaderScreen, ), Item( 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 eebcaa22c..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 @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material.icons.outlined.Close @@ -73,7 +72,7 @@ object SettingsTrackingScreen : SearchableSettings { val uriHandler = LocalUriHandler.current IconButton(onClick = { uriHandler.openUri("https://tachiyomi.org/docs/guides/tracking") }) { Icon( - imageVector = Icons.AutoMirrored.Outlined.HelpOutline, + imageVector = Icons.Outlined.HelpOutline, contentDescription = stringResource(R.string.tracking_guide), ) } diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt index 591d371cf..b1c3f2844 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt @@ -28,7 +28,6 @@ import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.ArrowBack import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material.icons.filled.Close @@ -98,7 +97,7 @@ fun TrackerSearch( navigationIcon = { IconButton(onClick = onDismissRequest) { Icon( - imageVector = Icons.AutoMirrored.Outlined.ArrowBack, + imageVector = Icons.Default.ArrowBack, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant, ) 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 50d387cf1..823b5bfc3 100644 --- a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt +++ b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt @@ -11,8 +11,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.ArrowBack -import androidx.compose.material.icons.automirrored.outlined.ArrowForward import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material.icons.outlined.ArrowForward import androidx.compose.material.icons.outlined.Close @@ -127,7 +125,7 @@ fun WebViewScreenContent( listOf( AppBar.Action( title = stringResource(R.string.action_webview_back), - icon = Icons.AutoMirrored.Outlined.ArrowBack, + icon = Icons.Outlined.ArrowBack, onClick = { if (navigator.canGoBack) { navigator.navigateBack() @@ -137,7 +135,7 @@ fun WebViewScreenContent( ), AppBar.Action( title = stringResource(R.string.action_webview_forward), - icon = Icons.AutoMirrored.Outlined.ArrowForward, + icon = Icons.Outlined.ArrowForward, onClick = { if (navigator.canGoForward) { navigator.navigateForward() @@ -188,7 +186,7 @@ fun WebViewScreenContent( .align(Alignment.BottomCenter), ) is LoadingState.Loading -> LinearProgressIndicator( - progress = { (loadingState as? LoadingState.Loading)?.progress ?: 1f }, + progress = (loadingState as? LoadingState.Loading)?.progress ?: 1f, modifier = Modifier .fillMaxWidth() .align(Alignment.BottomCenter), 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 8794c9078..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 @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.ui.browse.migration.sources import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -30,7 +29,7 @@ fun Screen.migrateSourceTab(): TabContent { actions = listOf( AppBar.Action( title = stringResource(R.string.migration_help_guide), - icon = Icons.AutoMirrored.Outlined.HelpOutline, + icon = Icons.Outlined.HelpOutline, onClick = { uriHandler.openUri("https://tachiyomi.org/docs/guides/source-migration") }, 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 0fc7f3576..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 @@ -10,7 +10,6 @@ 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.automirrored.outlined.Sort import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.icons.outlined.Pause import androidx.compose.material.icons.outlined.Sort @@ -186,7 +185,7 @@ object DownloadQueueScreen : Screen() { listOf( AppBar.Action( title = stringResource(R.string.action_sort), - icon = Icons.AutoMirrored.Outlined.Sort, + icon = Icons.Outlined.Sort, onClick = { sortExpanded = true }, ), AppBar.OverflowAction( 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 beab688e2..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 @@ -6,7 +6,6 @@ import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter import androidx.compose.animation.graphics.vector.AnimatedImageVector import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.HelpOutline import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState @@ -158,7 +157,7 @@ object LibraryTab : Tab { actions = listOf( EmptyScreenAction( stringResId = R.string.getting_started_guide, - icon = Icons.AutoMirrored.Outlined.HelpOutline, + icon = Icons.Outlined.HelpOutline, onClick = { handler.openUri("https://tachiyomi.org/docs/guides/getting-started") }, ), ), diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index ad2e6e603..26f0809d0 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,7 +1,7 @@ [versions] compiler = "1.5.3" -compose-bom = "2023.11.00-alpha02" -accompanist = "0.33.2-alpha" +compose-bom = "2023.09.00-alpha02" +accompanist = "0.33.1-alpha" [libraries] activity = "androidx.activity:activity-compose:1.8.0" From c46c39d4aea887503838cc832822047f3a41018a Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 27 Oct 2023 15:06:56 -0400 Subject: [PATCH 17/66] Rename "Backup and restore" settings screen to "Data and storage" We can house more things in here in the future, like: - A unified storage location setting (with scoped storage) - Sync - Disk usage info --- .../eu/kanade/presentation/more/MoreScreen.kt | 10 +- .../settings/screen/SettingsAdvancedScreen.kt | 31 ---- ...sBackupScreen.kt => SettingsDataScreen.kt} | 134 ++++++++++-------- .../settings/screen/SettingsMainScreen.kt | 8 +- .../settings/screen/SettingsSearchScreen.kt | 2 +- .../eu/kanade/tachiyomi/ui/more/MoreTab.kt | 2 +- .../tachiyomi/ui/setting/SettingsScreen.kt | 18 +-- i18n/src/main/res/values/strings.xml | 12 +- 8 files changed, 100 insertions(+), 117 deletions(-) rename app/src/main/java/eu/kanade/presentation/more/settings/screen/{SettingsBackupScreen.kt => SettingsDataScreen.kt} (86%) 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 5ef863c51..6f7e9e3d7 100644 --- a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt @@ -16,7 +16,7 @@ import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.Label import androidx.compose.material.icons.outlined.QueryStats import androidx.compose.material.icons.outlined.Settings -import androidx.compose.material.icons.outlined.SettingsBackupRestore +import androidx.compose.material.icons.outlined.Storage import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -45,7 +45,7 @@ fun MoreScreen( onClickDownloadQueue: () -> Unit, onClickCategories: () -> Unit, onClickStats: () -> Unit, - onClickBackupAndRestore: () -> Unit, + onClickDataAndStorage: () -> Unit, onClickSettings: () -> Unit, onClickAbout: () -> Unit, ) { @@ -141,9 +141,9 @@ fun MoreScreen( } item { TextPreferenceWidget( - title = stringResource(R.string.label_backup), - icon = Icons.Outlined.SettingsBackupRestore, - onPreferenceClick = onClickBackupAndRestore, + title = stringResource(R.string.label_data_storage), + icon = Icons.Outlined.Storage, + onPreferenceClick = onClickDataAndStorage, ) } 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 1b5d6a5c3..34e1981a9 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 @@ -14,7 +14,6 @@ import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -31,7 +30,6 @@ import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.more.settings.screen.advanced.ClearDatabaseScreen import eu.kanade.presentation.more.settings.screen.debug.DebugInfoScreen 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.network.NetworkHelper @@ -61,7 +59,6 @@ import okhttp3.Headers import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.system.logcat -import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.manga.repository.MangaRepository import tachiyomi.presentation.core.util.collectAsState import uy.kohesive.injekt.Injekt @@ -183,40 +180,12 @@ object SettingsAdvancedScreen : SearchableSettings { @Composable private fun getDataGroup(): Preference.PreferenceGroup { - val scope = rememberCoroutineScope() val context = LocalContext.current val navigator = LocalNavigator.currentOrThrow - val libraryPreferences = remember { Injekt.get() } - - val chapterCache = remember { Injekt.get() } - var readableSizeSema by remember { mutableIntStateOf(0) } - val readableSize = remember(readableSizeSema) { chapterCache.readableSize } return Preference.PreferenceGroup( title = stringResource(R.string.label_data), preferenceItems = listOf( - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_clear_chapter_cache), - subtitle = stringResource(R.string.used_cache, readableSize), - onClick = { - scope.launchNonCancellable { - try { - val deletedFiles = chapterCache.clear() - withUIContext { - context.toast(context.getString(R.string.cache_deleted, deletedFiles)) - readableSizeSema++ - } - } catch (e: Throwable) { - logcat(LogPriority.ERROR, e) - withUIContext { context.toast(R.string.cache_delete_error) } - } - } - }, - ), - Preference.PreferenceItem.SwitchPreference( - pref = libraryPreferences.autoClearChapterCache(), - title = stringResource(R.string.pref_auto_clear_chapter_cache), - ), Preference.PreferenceItem.TextPreference( title = stringResource(R.string.pref_invalidate_download_cache), subtitle = stringResource(R.string.pref_invalidate_download_cache_summary), 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/SettingsDataScreen.kt similarity index 86% rename from app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt rename to app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt index cb9c9907c..75c1cf467 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/SettingsDataScreen.kt @@ -31,8 +31,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.core.net.toUri -import com.hippo.unifile.UniFile import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.permissions.PermissionRequestHelper import eu.kanade.tachiyomi.R @@ -41,11 +39,17 @@ import eu.kanade.tachiyomi.data.backup.BackupCreateJob import eu.kanade.tachiyomi.data.backup.BackupFileValidator import eu.kanade.tachiyomi.data.backup.BackupRestoreJob import eu.kanade.tachiyomi.data.backup.models.Backup +import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.toast import kotlinx.coroutines.launch +import logcat.LogPriority +import tachiyomi.core.util.lang.launchNonCancellable +import tachiyomi.core.util.lang.withUIContext +import tachiyomi.core.util.system.logcat import tachiyomi.domain.backup.service.BackupPreferences +import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.presentation.core.components.LabeledCheckbox import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.util.collectAsState @@ -54,12 +58,12 @@ import tachiyomi.presentation.core.util.isScrolledToStart import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -object SettingsBackupScreen : SearchableSettings { +object SettingsDataScreen : SearchableSettings { @ReadOnlyComposable @Composable @StringRes - override fun getTitleRes() = R.string.label_backup + override fun getTitleRes() = R.string.label_data_storage @Composable override fun getPreferences(): List { @@ -68,9 +72,49 @@ object SettingsBackupScreen : SearchableSettings { PermissionRequestHelper.requestStoragePermission() return listOf( - getCreateBackupPref(), - getRestoreBackupPref(), - getAutomaticBackupGroup(backupPreferences = backupPreferences), + getBackupAndRestoreGroup(backupPreferences = backupPreferences), + getDataGroup(), + ) + } + + @Composable + private fun getBackupAndRestoreGroup(backupPreferences: BackupPreferences): Preference.PreferenceGroup { + val context = LocalContext.current + val backupIntervalPref = backupPreferences.backupInterval() + val backupInterval by backupIntervalPref.collectAsState() + + return Preference.PreferenceGroup( + title = stringResource(R.string.label_backup), + preferenceItems = listOf( + // Manual actions + getCreateBackupPref(), + getRestoreBackupPref(), + + // Automatic backups + Preference.PreferenceItem.ListPreference( + pref = backupIntervalPref, + title = stringResource(R.string.pref_backup_interval), + entries = mapOf( + 0 to stringResource(R.string.off), + 6 to stringResource(R.string.update_6hour), + 12 to stringResource(R.string.update_12hour), + 24 to stringResource(R.string.update_24hour), + 48 to stringResource(R.string.update_48hour), + 168 to stringResource(R.string.update_weekly), + ), + onValueChanged = { + BackupCreateJob.setupTask(context, it) + true + }, + ), + Preference.PreferenceItem.ListPreference( + pref = backupPreferences.numberOfBackups(), + enabled = backupInterval != 0, + title = stringResource(R.string.pref_backup_slots), + entries = listOf(2, 3, 4, 5).associateWith { it.toString() }, + ), + Preference.PreferenceItem.InfoPreference(stringResource(R.string.backup_info)), + ), ) } @@ -318,70 +362,40 @@ object SettingsBackupScreen : SearchableSettings { } @Composable - private fun getAutomaticBackupGroup( - backupPreferences: BackupPreferences, - ): Preference.PreferenceGroup { + private fun getDataGroup(): Preference.PreferenceGroup { + val scope = rememberCoroutineScope() val context = LocalContext.current - val backupIntervalPref = backupPreferences.backupInterval() - val backupInterval by backupIntervalPref.collectAsState() - val backupDirPref = backupPreferences.backupsDirectory() - val backupDir by backupDirPref.collectAsState() - val pickBackupLocation = rememberLauncherForActivityResult( - contract = ActivityResultContracts.OpenDocumentTree(), - ) { uri -> - if (uri != null) { - val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION + val libraryPreferences = remember { Injekt.get() } - context.contentResolver.takePersistableUriPermission(uri, flags) - - val file = UniFile.fromUri(context, uri) - backupDirPref.set(file.uri.toString()) - } - } + val chapterCache = remember { Injekt.get() } + var readableSizeSema by remember { mutableIntStateOf(0) } + val readableSize = remember(readableSizeSema) { chapterCache.readableSize } return Preference.PreferenceGroup( - title = stringResource(R.string.pref_backup_service_category), + title = stringResource(R.string.label_data), preferenceItems = listOf( - Preference.PreferenceItem.ListPreference( - pref = backupIntervalPref, - title = stringResource(R.string.pref_backup_interval), - entries = mapOf( - 0 to stringResource(R.string.off), - 6 to stringResource(R.string.update_6hour), - 12 to stringResource(R.string.update_12hour), - 24 to stringResource(R.string.update_24hour), - 48 to stringResource(R.string.update_48hour), - 168 to stringResource(R.string.update_weekly), - ), - onValueChanged = { - BackupCreateJob.setupTask(context, it) - true - }, - ), Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_backup_directory), - enabled = backupInterval != 0, - subtitle = remember(backupDir) { - (UniFile.fromUri(context, backupDir.toUri())?.filePath)?.let { - "$it/automatic" - } - } ?: stringResource(R.string.invalid_location, backupDir), + title = stringResource(R.string.pref_clear_chapter_cache), + subtitle = stringResource(R.string.used_cache, readableSize), onClick = { - try { - pickBackupLocation.launch(null) - } catch (e: ActivityNotFoundException) { - context.toast(R.string.file_picker_error) + scope.launchNonCancellable { + try { + val deletedFiles = chapterCache.clear() + withUIContext { + context.toast(context.getString(R.string.cache_deleted, deletedFiles)) + readableSizeSema++ + } + } catch (e: Throwable) { + logcat(LogPriority.ERROR, e) + withUIContext { context.toast(R.string.cache_delete_error) } + } } }, ), - Preference.PreferenceItem.ListPreference( - pref = backupPreferences.numberOfBackups(), - enabled = backupInterval != 0, - title = stringResource(R.string.pref_backup_slots), - entries = listOf(2, 3, 4, 5).associateWith { it.toString() }, + Preference.PreferenceItem.SwitchPreference( + pref = libraryPreferences.autoClearChapterCache(), + title = stringResource(R.string.pref_auto_clear_chapter_cache), ), - Preference.PreferenceItem.InfoPreference(stringResource(R.string.backup_info)), ), ) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt index 5f9c4e9b5..ea9c61a32 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt @@ -18,7 +18,7 @@ import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.Palette import androidx.compose.material.icons.outlined.Search import androidx.compose.material.icons.outlined.Security -import androidx.compose.material.icons.outlined.SettingsBackupRestore +import androidx.compose.material.icons.outlined.Storage import androidx.compose.material.icons.outlined.Sync import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme @@ -208,10 +208,10 @@ object SettingsMainScreen : Screen() { screen = SettingsBrowseScreen, ), Item( - titleRes = R.string.label_backup, + titleRes = R.string.label_data_storage, subtitleRes = R.string.pref_backup_summary, - icon = Icons.Outlined.SettingsBackupRestore, - screen = SettingsBackupScreen, + icon = Icons.Outlined.Storage, + screen = SettingsDataScreen, ), Item( titleRes = R.string.pref_category_security, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt index 420722ccc..b67ac38c5 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt @@ -291,7 +291,7 @@ private val settingScreens = listOf( SettingsDownloadScreen, SettingsTrackingScreen, SettingsBrowseScreen, - SettingsBackupScreen, + SettingsDataScreen, SettingsSecurityScreen, SettingsAdvancedScreen, ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreTab.kt index 2870b8c44..8179fe68d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreTab.kt @@ -71,7 +71,7 @@ object MoreTab : Tab { onClickDownloadQueue = { navigator.push(DownloadQueueScreen) }, onClickCategories = { navigator.push(CategoryScreen()) }, onClickStats = { navigator.push(StatsScreen()) }, - onClickBackupAndRestore = { navigator.push(SettingsScreen.toBackupScreen()) }, + onClickDataAndStorage = { navigator.push(SettingsScreen.toDataAndStorageScreen()) }, onClickSettings = { navigator.push(SettingsScreen.toMainScreen()) }, onClickAbout = { navigator.push(SettingsScreen.toAboutScreen()) }, ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsScreen.kt index 5a6d05025..5b2dcedb2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsScreen.kt @@ -13,7 +13,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.more.settings.screen.SettingsAppearanceScreen -import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen +import eu.kanade.presentation.more.settings.screen.SettingsDataScreen import eu.kanade.presentation.more.settings.screen.SettingsMainScreen import eu.kanade.presentation.more.settings.screen.about.AboutScreen import eu.kanade.presentation.util.DefaultNavigatorScreenTransition @@ -23,7 +23,7 @@ import eu.kanade.presentation.util.isTabletUi import tachiyomi.presentation.core.components.TwoPanelBox class SettingsScreen private constructor( - val toBackup: Boolean, + val toDataAndStorage: Boolean, val toAbout: Boolean, ) : Screen() { @@ -32,8 +32,8 @@ class SettingsScreen private constructor( val parentNavigator = LocalNavigator.currentOrThrow if (!isTabletUi()) { Navigator( - screen = if (toBackup) { - SettingsBackupScreen + screen = if (toDataAndStorage) { + SettingsDataScreen } else if (toAbout) { AboutScreen } else { @@ -54,8 +54,8 @@ class SettingsScreen private constructor( ) } else { Navigator( - screen = if (toBackup) { - SettingsBackupScreen + screen = if (toDataAndStorage) { + SettingsDataScreen } else if (toAbout) { AboutScreen } else { @@ -79,10 +79,10 @@ class SettingsScreen private constructor( } companion object { - fun toMainScreen() = SettingsScreen(toBackup = false, toAbout = false) + fun toMainScreen() = SettingsScreen(toDataAndStorage = false, toAbout = false) - fun toBackupScreen() = SettingsScreen(toBackup = true, toAbout = false) + fun toDataAndStorageScreen() = SettingsScreen(toDataAndStorage = true, toAbout = false) - fun toAboutScreen() = SettingsScreen(toBackup = false, toAbout = true) + fun toAboutScreen() = SettingsScreen(toDataAndStorage = false, toAbout = true) } } diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 8c7ff8736..76fa240b7 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -24,6 +24,7 @@ History Sources Backup and restore + Data and storage Statistics Migrate Extensions @@ -181,7 +182,7 @@ Automatic download, download ahead One-way progress sync, enhanced sync Sources, extensions, global search - Manual & automatic backups + Manual & automatic backups, storage space App lock, secure screen Dump crash logs, battery optimizations @@ -467,15 +468,14 @@ Hide entries already in library - + Create backup Can be used to restore current library Restore backup Restore library from backup file Backup location - Automatic backups - Backup frequency - Maximum backups + Automatic backup frequency + Maximum automatic backups Backup created Invalid backup file Backup does not contain any library entries. @@ -509,7 +509,7 @@ Library sync complete - Network + Networking Clear cookies DNS over HTTPS (DoH) Default user agent string From eed57b80be077a9f73c36d8dc572f34f59c1ba8d Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 27 Oct 2023 15:37:59 -0400 Subject: [PATCH 18/66] Replace AppUpdateService with a WorkManager job Fixes #7773 Co-authored-by: Jays2Kings --- app/src/main/AndroidManifest.xml | 4 - .../data/notification/NotificationReceiver.kt | 29 ++- .../data/updater/AppUpdateDownloadJob.kt | 148 +++++++++++++ .../data/updater/AppUpdateNotifier.kt | 14 +- .../data/updater/AppUpdateService.kt | 195 ------------------ .../tachiyomi/ui/more/NewUpdateScreen.kt | 4 +- 6 files changed, 183 insertions(+), 211 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateDownloadJob.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c3c2f288c..442a123f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -145,10 +145,6 @@ android:name=".data.download.DownloadService" android:exported="false" /> - - diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index 5110aaca6..566da8e9c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.BackupRestoreJob import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.library.LibraryUpdateJob -import eu.kanade.tachiyomi.data.updater.AppUpdateService +import eu.kanade.tachiyomi.data.updater.AppUpdateDownloadJob import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.util.storage.DiskUtil @@ -85,6 +85,8 @@ class NotificationReceiver : BroadcastReceiver() { ACTION_CANCEL_RESTORE -> cancelRestore(context) // Cancel library update and dismiss notification ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context) + // Start downloading app update + ACTION_START_APP_UPDATE -> startDownloadAppUpdate(context, intent) // Cancel downloading app update ACTION_CANCEL_APP_UPDATE_DOWNLOAD -> cancelDownloadAppUpdate(context) // Open reader activity @@ -209,8 +211,13 @@ class NotificationReceiver : BroadcastReceiver() { LibraryUpdateJob.stop(context) } + private fun startDownloadAppUpdate(context: Context, intent: Intent) { + val url = intent.getStringExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_URL) ?: return + AppUpdateDownloadJob.start(context, url) + } + private fun cancelDownloadAppUpdate(context: Context) { - AppUpdateService.stop(context) + AppUpdateDownloadJob.stop(context) } /** @@ -268,6 +275,7 @@ class NotificationReceiver : BroadcastReceiver() { private const val ACTION_CANCEL_LIBRARY_UPDATE = "$ID.$NAME.CANCEL_LIBRARY_UPDATE" + private const val ACTION_START_APP_UPDATE = "$ID.$NAME.ACTION_START_APP_UPDATE" private const val ACTION_CANCEL_APP_UPDATE_DOWNLOAD = "$ID.$NAME.CANCEL_APP_UPDATE_DOWNLOAD" private const val ACTION_MARK_AS_READ = "$ID.$NAME.MARK_AS_READ" @@ -499,10 +507,25 @@ class NotificationReceiver : BroadcastReceiver() { return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) } + /** + * Returns [PendingIntent] that starts the [AppUpdateDownloadJob] to download an app update. + * + * @param context context of application + * @return [PendingIntent] + */ + internal fun downloadAppUpdatePendingBroadcast(context: Context, url: String, title: String? = null): PendingIntent { + return Intent(context, NotificationReceiver::class.java).run { + action = ACTION_START_APP_UPDATE + putExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_URL, url) + title?.let { putExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_TITLE, it) } + PendingIntent.getBroadcast(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + } + } + /** * */ - internal fun cancelUpdateDownloadPendingBroadcast(context: Context): PendingIntent { + internal fun cancelDownloadAppUpdatePendingBroadcast(context: Context): PendingIntent { val intent = Intent(context, NotificationReceiver::class.java).apply { action = ACTION_CANCEL_APP_UPDATE_DOWNLOAD } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateDownloadJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateDownloadJob.kt new file mode 100644 index 000000000..60d5e71ec --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateDownloadJob.kt @@ -0,0 +1,148 @@ +package eu.kanade.tachiyomi.data.updater + +import android.content.Context +import androidx.work.Constraints +import androidx.work.CoroutineWorker +import androidx.work.ExistingWorkPolicy +import androidx.work.ForegroundInfo +import androidx.work.NetworkType +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.notification.Notifications +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.NetworkHelper +import eu.kanade.tachiyomi.network.ProgressListener +import eu.kanade.tachiyomi.network.await +import eu.kanade.tachiyomi.network.newCachelessCallWithProgress +import eu.kanade.tachiyomi.util.storage.getUriCompat +import eu.kanade.tachiyomi.util.storage.saveTo +import eu.kanade.tachiyomi.util.system.workManager +import logcat.LogPriority +import okhttp3.internal.http2.ErrorCode +import okhttp3.internal.http2.StreamResetException +import tachiyomi.core.util.lang.withIOContext +import tachiyomi.core.util.system.logcat +import uy.kohesive.injekt.injectLazy +import java.io.File +import kotlin.coroutines.cancellation.CancellationException + +class AppUpdateDownloadJob(private val context: Context, workerParams: WorkerParameters) : + CoroutineWorker(context, workerParams) { + + private val notifier = AppUpdateNotifier(context) + private val network: NetworkHelper by injectLazy() + + override suspend fun doWork(): Result { + val url = inputData.getString(EXTRA_DOWNLOAD_URL) + val title = inputData.getString(EXTRA_DOWNLOAD_TITLE) ?: context.getString(R.string.app_name) + + if (url.isNullOrEmpty()) { + return Result.failure() + } + + try { + setForeground(getForegroundInfo()) + } catch (e: IllegalStateException) { + logcat(LogPriority.ERROR, e) { "Not allowed to run on foreground service" } + } + + withIOContext { + downloadApk(title, url) + } + + return Result.success() + } + + override suspend fun getForegroundInfo(): ForegroundInfo { + return ForegroundInfo( + Notifications.ID_APP_UPDATER, + notifier.onDownloadStarted().build(), + ) + } + + /** + * Called to start downloading apk of new update + * + * @param url url location of file + */ + private suspend fun downloadApk(title: String, url: String) { + // Show notification download starting. + notifier.onDownloadStarted(title) + + val progressListener = object : ProgressListener { + // Progress of the download + var savedProgress = 0 + + // Keep track of the last notification sent to avoid posting too many. + var lastTick = 0L + + override fun update(bytesRead: Long, contentLength: Long, done: Boolean) { + val progress = (100 * (bytesRead.toFloat() / contentLength)).toInt() + val currentTime = System.currentTimeMillis() + if (progress > savedProgress && currentTime - 200 > lastTick) { + savedProgress = progress + lastTick = currentTime + notifier.onProgressChange(progress) + } + } + } + + try { + // Download the new update. + val response = network.client.newCachelessCallWithProgress(GET(url), progressListener) + .await() + + // File where the apk will be saved. + val apkFile = File(context.externalCacheDir, "update.apk") + + if (response.isSuccessful) { + response.body.source().saveTo(apkFile) + } else { + response.close() + throw Exception("Unsuccessful response") + } + notifier.cancel() + notifier.promptInstall(apkFile.getUriCompat(context)) + } catch (e: Exception) { + val shouldCancel = e is CancellationException || + (e is StreamResetException && e.errorCode == ErrorCode.CANCEL) + if (shouldCancel) { + notifier.cancel() + } else { + notifier.onDownloadError(url) + } + } + } + + companion object { + private const val TAG = "AppUpdateDownload" + + const val EXTRA_DOWNLOAD_URL = "DOWNLOAD_URL" + const val EXTRA_DOWNLOAD_TITLE = "DOWNLOAD_TITLE" + + fun start(context: Context, url: String, title: String? = null) { + val constraints = Constraints( + requiredNetworkType = NetworkType.CONNECTED, + ) + + val request = OneTimeWorkRequestBuilder() + .setConstraints(constraints) + .addTag(TAG) + .setInputData( + workDataOf( + EXTRA_DOWNLOAD_URL to url, + EXTRA_DOWNLOAD_TITLE to title, + ), + ) + .build() + + context.workManager.enqueueUniqueWork(TAG, ExistingWorkPolicy.REPLACE, request) + } + + fun stop(context: Context) { + context.workManager.cancelUniqueWork(TAG) + } + } +} 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 728967654..0437103a3 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 @@ -34,11 +34,11 @@ internal class AppUpdateNotifier(private val context: Context) { @SuppressLint("LaunchActivityFromNotification") fun promptUpdate(release: Release) { - val updateIntent = Intent(context, AppUpdateService::class.java).run { - putExtra(AppUpdateService.EXTRA_DOWNLOAD_URL, release.getDownloadLink()) - putExtra(AppUpdateService.EXTRA_DOWNLOAD_TITLE, release.version) - PendingIntent.getService(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - } + val updateIntent = NotificationReceiver.downloadAppUpdatePendingBroadcast( + context, + release.getDownloadLink(), + release.version, + ) val releaseIntent = Intent(Intent.ACTION_VIEW, release.releaseLink.toUri()).run { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP @@ -82,7 +82,7 @@ internal class AppUpdateNotifier(private val context: Context) { addAction( R.drawable.ic_close_24dp, context.getString(R.string.action_cancel), - NotificationReceiver.cancelUpdateDownloadPendingBroadcast(context), + NotificationReceiver.cancelDownloadAppUpdatePendingBroadcast(context), ) } notificationBuilder.show() @@ -164,7 +164,7 @@ internal class AppUpdateNotifier(private val context: Context) { addAction( R.drawable.ic_refresh_24dp, context.getString(R.string.action_retry), - AppUpdateService.downloadApkPendingService(context, url), + NotificationReceiver.downloadAppUpdatePendingBroadcast(context, url), ) addAction( R.drawable.ic_close_24dp, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt deleted file mode 100644 index c1f973d2d..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt +++ /dev/null @@ -1,195 +0,0 @@ -package eu.kanade.tachiyomi.data.updater - -import android.app.PendingIntent -import android.app.Service -import android.content.Context -import android.content.Intent -import android.os.IBinder -import android.os.PowerManager -import androidx.core.content.ContextCompat -import eu.kanade.tachiyomi.BuildConfig -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.notification.Notifications -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.NetworkHelper -import eu.kanade.tachiyomi.network.ProgressListener -import eu.kanade.tachiyomi.network.await -import eu.kanade.tachiyomi.network.newCachelessCallWithProgress -import eu.kanade.tachiyomi.util.storage.getUriCompat -import eu.kanade.tachiyomi.util.storage.saveTo -import eu.kanade.tachiyomi.util.system.acquireWakeLock -import eu.kanade.tachiyomi.util.system.isServiceRunning -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch -import okhttp3.internal.http2.ErrorCode -import okhttp3.internal.http2.StreamResetException -import uy.kohesive.injekt.injectLazy -import java.io.File - -class AppUpdateService : Service() { - - private val network: NetworkHelper by injectLazy() - - /** - * Wake lock that will be held until the service is destroyed. - */ - private lateinit var wakeLock: PowerManager.WakeLock - private lateinit var notifier: AppUpdateNotifier - - private val job = SupervisorJob() - private val serviceScope = CoroutineScope(Dispatchers.IO + job) - - override fun onCreate() { - notifier = AppUpdateNotifier(this) - wakeLock = acquireWakeLock(javaClass.name) - - startForeground(Notifications.ID_APP_UPDATER, notifier.onDownloadStarted().build()) - } - - /** - * This method needs to be implemented, but it's not used/needed. - */ - override fun onBind(intent: Intent): IBinder? = null - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - if (intent == null) return START_NOT_STICKY - - val url = intent.getStringExtra(EXTRA_DOWNLOAD_URL) ?: return START_NOT_STICKY - val title = intent.getStringExtra(EXTRA_DOWNLOAD_TITLE) ?: getString(R.string.app_name) - - serviceScope.launch { - downloadApk(title, url) - } - - job.invokeOnCompletion { stopSelf(startId) } - return START_NOT_STICKY - } - - override fun stopService(name: Intent?): Boolean { - destroyJob() - return super.stopService(name) - } - - override fun onDestroy() { - destroyJob() - } - - private fun destroyJob() { - serviceScope.cancel() - job.cancel() - if (wakeLock.isHeld) { - wakeLock.release() - } - } - - /** - * Called to start downloading apk of new update - * - * @param url url location of file - */ - private suspend fun downloadApk(title: String, url: String) { - // Show notification download starting. - notifier.onDownloadStarted(title) - - val progressListener = object : ProgressListener { - // Progress of the download - var savedProgress = 0 - - // Keep track of the last notification sent to avoid posting too many. - var lastTick = 0L - - override fun update(bytesRead: Long, contentLength: Long, done: Boolean) { - val progress = (100 * (bytesRead.toFloat() / contentLength)).toInt() - val currentTime = System.currentTimeMillis() - if (progress > savedProgress && currentTime - 200 > lastTick) { - savedProgress = progress - lastTick = currentTime - notifier.onProgressChange(progress) - } - } - } - - try { - // Download the new update. - val response = network.client.newCachelessCallWithProgress(GET(url), progressListener) - .await() - - // File where the apk will be saved. - val apkFile = File(externalCacheDir, "update.apk") - - if (response.isSuccessful) { - response.body.source().saveTo(apkFile) - } else { - response.close() - throw Exception("Unsuccessful response") - } - notifier.cancel() - notifier.promptInstall(apkFile.getUriCompat(this)) - } catch (e: Exception) { - val shouldCancel = e is CancellationException || - (e is StreamResetException && e.errorCode == ErrorCode.CANCEL) - if (shouldCancel) { - notifier.cancel() - } else { - notifier.onDownloadError(url) - } - } - } - - companion object { - - internal const val EXTRA_DOWNLOAD_URL = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_URL" - internal const val EXTRA_DOWNLOAD_TITLE = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_TITLE" - - /** - * Returns the status of the service. - * - * @param context the application context. - * @return true if the service is running, false otherwise. - */ - private fun isRunning(context: Context): Boolean = - context.isServiceRunning(AppUpdateService::class.java) - - /** - * Downloads a new update and let the user install the new version from a notification. - * - * @param context the application context. - * @param url the url to the new update. - */ - fun start(context: Context, url: String, title: String? = context.getString(R.string.app_name)) { - if (isRunning(context)) return - - Intent(context, AppUpdateService::class.java).apply { - putExtra(EXTRA_DOWNLOAD_TITLE, title) - putExtra(EXTRA_DOWNLOAD_URL, url) - ContextCompat.startForegroundService(context, this) - } - } - - /** - * Stops the service. - * - * @param context the application context - */ - fun stop(context: Context) { - context.stopService(Intent(context, AppUpdateService::class.java)) - } - - /** - * Returns [PendingIntent] that starts a service which downloads the apk specified in url. - * - * @param url the url to the new update. - * @return [PendingIntent] - */ - internal fun downloadApkPendingService(context: Context, url: String): PendingIntent { - return Intent(context, AppUpdateService::class.java).run { - putExtra(EXTRA_DOWNLOAD_URL, url) - PendingIntent.getService(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - } - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/NewUpdateScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/NewUpdateScreen.kt index f6ebdab64..eae88d838 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/NewUpdateScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/NewUpdateScreen.kt @@ -7,7 +7,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.more.NewUpdateScreen import eu.kanade.presentation.util.Screen -import eu.kanade.tachiyomi.data.updater.AppUpdateService +import eu.kanade.tachiyomi.data.updater.AppUpdateDownloadJob import eu.kanade.tachiyomi.util.system.openInBrowser class NewUpdateScreen( @@ -31,7 +31,7 @@ class NewUpdateScreen( onOpenInBrowser = { context.openInBrowser(releaseLink) }, onRejectUpdate = navigator::pop, onAcceptUpdate = { - AppUpdateService.start( + AppUpdateDownloadJob.start( context = context, url = downloadLink, title = versionName, From 118d3b7fcc5cf8a27e52ff690cb3ecd28860c10c Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 28 Oct 2023 15:28:39 -0400 Subject: [PATCH 19/66] Add ability to reset chapter flags to defaults Closes #10063 --- .../kanade/domain/manga/interactor/SetMangaViewerFlags.kt | 4 ++-- .../eu/kanade/presentation/manga/ChapterSettingsDialog.kt | 8 ++++++++ .../more/settings/screen/SettingsAdvancedScreen.kt | 4 ++-- .../main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt | 1 + .../java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt | 7 +++++++ .../java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt | 4 ++-- data/src/main/sqldelight/tachiyomi/data/mangas.sq | 6 ++++-- 7 files changed, 26 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/SetMangaViewerFlags.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/SetMangaViewerFlags.kt index 521be8b8c..8ffc27bb9 100644 --- a/app/src/main/java/eu/kanade/domain/manga/interactor/SetMangaViewerFlags.kt +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/SetMangaViewerFlags.kt @@ -9,7 +9,7 @@ class SetMangaViewerFlags( private val mangaRepository: MangaRepository, ) { - suspend fun awaitSetMangaReadingMode(id: Long, flag: Long) { + suspend fun awaitSetReadingMode(id: Long, flag: Long) { val manga = mangaRepository.getMangaById(id) mangaRepository.update( MangaUpdate( @@ -19,7 +19,7 @@ class SetMangaViewerFlags( ) } - suspend fun awaitSetOrientationType(id: Long, flag: Long) { + suspend fun awaitSetOrientation(id: Long, flag: Long) { val manga = mangaRepository.getMangaById(id) mangaRepository.update( MangaUpdate( diff --git a/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt index 9f842fead..b90a86fa5 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt @@ -40,6 +40,7 @@ fun ChapterSettingsDialog( onSortModeChanged: (Long) -> Unit, onDisplayModeChanged: (Long) -> Unit, onSetAsDefault: (applyToExistingManga: Boolean) -> Unit, + onResetToDefault: () -> Unit, ) { var showSetAsDefaultDialog by rememberSaveable { mutableStateOf(false) } if (showSetAsDefaultDialog) { @@ -64,6 +65,13 @@ fun ChapterSettingsDialog( closeMenu() }, ) + DropdownMenuItem( + text = { Text(stringResource(R.string.action_reset)) }, + onClick = { + onResetToDefault() + closeMenu() + }, + ) }, ) { page -> Column( 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 34e1981a9..97d852e50 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 @@ -59,7 +59,7 @@ import okhttp3.Headers import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.system.logcat -import tachiyomi.domain.manga.repository.MangaRepository +import tachiyomi.domain.manga.interactor.ResetViewerFlags import tachiyomi.presentation.core.util.collectAsState import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -309,7 +309,7 @@ object SettingsAdvancedScreen : SearchableSettings { subtitle = stringResource(R.string.pref_reset_viewer_flags_summary), onClick = { scope.launchNonCancellable { - val success = Injekt.get().resetViewerFlags() + val success = Injekt.get().await() withUIContext { val message = if (success) { R.string.pref_reset_viewer_flags_success 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 39595fbe5..f16767a49 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 @@ -172,6 +172,7 @@ class MangaScreen( onSortModeChanged = screenModel::setSorting, onDisplayModeChanged = screenModel::setDisplayMode, onSetAsDefault = screenModel::setCurrentSettingsAsDefault, + onResetToDefault = screenModel::resetToDefaultSettings, ) MangaScreenModel.Dialog.TrackSheet -> { NavigatorAdaptiveSheet( 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 95feba487..a4f6f5d95 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 @@ -834,6 +834,13 @@ class MangaScreenModel( } } + fun resetToDefaultSettings() { + val manga = successState?.manga ?: return + screenModelScope.launchNonCancellable { + setMangaDefaultChapterFlags.await(manga) + } + } + fun toggleSelection( item: ChapterItem, selected: 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 555bdef3a..d1c91b62a 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 @@ -630,7 +630,7 @@ class ReaderViewModel @JvmOverloads constructor( fun setMangaReadingMode(readingModeType: ReadingModeType) { val manga = manga ?: return runBlocking(Dispatchers.IO) { - setMangaViewerFlags.awaitSetMangaReadingMode(manga.id, readingModeType.flagValue.toLong()) + setMangaViewerFlags.awaitSetReadingMode(manga.id, readingModeType.flagValue.toLong()) val currChapters = state.value.viewerChapters if (currChapters != null) { // Save current page @@ -666,7 +666,7 @@ class ReaderViewModel @JvmOverloads constructor( fun setMangaOrientationType(rotationType: OrientationType) { val manga = manga ?: return viewModelScope.launchIO { - setMangaViewerFlags.awaitSetOrientationType(manga.id, rotationType.flagValue.toLong()) + setMangaViewerFlags.awaitSetOrientation(manga.id, rotationType.flagValue.toLong()) val currChapters = state.value.viewerChapters if (currChapters != null) { // Save current page diff --git a/data/src/main/sqldelight/tachiyomi/data/mangas.sq b/data/src/main/sqldelight/tachiyomi/data/mangas.sq index 7260332de..220b908ad 100644 --- a/data/src/main/sqldelight/tachiyomi/data/mangas.sq +++ b/data/src/main/sqldelight/tachiyomi/data/mangas.sq @@ -57,7 +57,8 @@ WHERE _id = :id; getMangaByUrlAndSource: SELECT * FROM mangas -WHERE url = :url AND source = :source +WHERE url = :url +AND source = :source LIMIT 1; getFavorites: @@ -107,7 +108,8 @@ GROUP BY source; deleteMangasNotInLibraryBySourceIds: DELETE FROM mangas -WHERE favorite = 0 AND source IN :sourceIds; +WHERE favorite = 0 +AND source IN :sourceIds; insert: INSERT INTO mangas(source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, update_strategy, calculate_interval, last_modified_at) From d80ba2e807ae6701f7bcd40036c37b5b521b017f Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sat, 28 Oct 2023 21:35:23 +0200 Subject: [PATCH 20/66] Translations update from Hosted Weblate (#10043) 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/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/ko/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ro/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/ 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/zh_Hans/ Translation: Tachiyomi/Tachiyomi 0.x Co-authored-by: Ahmed Sameh Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> Co-authored-by: Ali Aljishi Co-authored-by: Bicycle Co-authored-by: Dexroneum Co-authored-by: Eduard Ereza Martínez Co-authored-by: InfinityDouki56 Co-authored-by: Jueon Park Co-authored-by: Lyfja Co-authored-by: Milo Ivir Co-authored-by: Pitpe11 Co-authored-by: Saft Octavian Co-authored-by: Swyter Co-authored-by: TheKingTermux Co-authored-by: Zero O Co-authored-by: altinat Co-authored-by: bapeey Co-authored-by: gallegonovato Co-authored-by: orkan gökçe alaz aşina --- i18n/src/main/res/values-am/strings.xml | 1 - i18n/src/main/res/values-ar/strings.xml | 26 ++++++++----------- i18n/src/main/res/values-b+es+419/strings.xml | 10 +++---- i18n/src/main/res/values-be/strings.xml | 2 -- 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 | 6 +---- i18n/src/main/res/values-ceb/strings.xml | 5 ---- i18n/src/main/res/values-cs/strings.xml | 5 ---- i18n/src/main/res/values-cv/strings.xml | 5 ---- i18n/src/main/res/values-da/strings.xml | 2 -- i18n/src/main/res/values-de/strings.xml | 8 ++---- i18n/src/main/res/values-el/strings.xml | 6 +---- i18n/src/main/res/values-eo/strings.xml | 4 --- i18n/src/main/res/values-es/strings.xml | 12 +++------ 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 | 8 ++---- i18n/src/main/res/values-fr/strings.xml | 5 ---- i18n/src/main/res/values-gl/strings.xml | 5 ---- i18n/src/main/res/values-he/strings.xml | 5 ---- i18n/src/main/res/values-hi/strings.xml | 5 ---- i18n/src/main/res/values-hr/strings.xml | 14 ++++------ i18n/src/main/res/values-hu/strings.xml | 5 ---- i18n/src/main/res/values-in/strings.xml | 17 ++++++------ i18n/src/main/res/values-it/strings.xml | 8 ++---- i18n/src/main/res/values-ja/strings.xml | 7 +---- i18n/src/main/res/values-jv/strings.xml | 2 -- i18n/src/main/res/values-ka-rGE/strings.xml | 3 --- i18n/src/main/res/values-kk/strings.xml | 5 ---- i18n/src/main/res/values-kn/strings.xml | 5 ---- i18n/src/main/res/values-ko/strings.xml | 22 ++++++++-------- i18n/src/main/res/values-lt/strings.xml | 5 ---- i18n/src/main/res/values-lv/strings.xml | 5 ---- i18n/src/main/res/values-ms/strings.xml | 5 ---- 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 | 1 - i18n/src/main/res/values-pl/strings.xml | 5 ---- i18n/src/main/res/values-pt-rBR/strings.xml | 12 +++------ i18n/src/main/res/values-pt/strings.xml | 5 ---- i18n/src/main/res/values-ro/strings.xml | 7 ++--- i18n/src/main/res/values-ru/strings.xml | 7 +---- i18n/src/main/res/values-sa/strings.xml | 5 ---- i18n/src/main/res/values-sah/strings.xml | 3 --- i18n/src/main/res/values-sc/strings.xml | 5 ---- i18n/src/main/res/values-sk/strings.xml | 5 ---- i18n/src/main/res/values-sq/strings.xml | 5 ---- i18n/src/main/res/values-sr/strings.xml | 5 ---- i18n/src/main/res/values-sv/strings.xml | 5 ---- i18n/src/main/res/values-th/strings.xml | 6 +---- i18n/src/main/res/values-tr/strings.xml | 25 ++++++++++-------- i18n/src/main/res/values-uk/strings.xml | 5 ---- i18n/src/main/res/values-uz/strings.xml | 2 -- i18n/src/main/res/values-vi/strings.xml | 5 ---- i18n/src/main/res/values-zh-rCN/strings.xml | 23 +++++++++------- i18n/src/main/res/values-zh-rTW/strings.xml | 5 ---- 59 files changed, 87 insertions(+), 317 deletions(-) diff --git a/i18n/src/main/res/values-am/strings.xml b/i18n/src/main/res/values-am/strings.xml index 60b800dd0..07486c308 100644 --- a/i18n/src/main/res/values-am/strings.xml +++ b/i18n/src/main/res/values-am/strings.xml @@ -256,7 +256,6 @@ ምትኬ ተፈጥሯል ከፍተኛ መጠባበቂያዎች የመጠባበቂያ ድግግሞሽ - ራስ-ሰር መጠባበቂያዎች የመጠባበቂያ ቦታ ቤተ-መጽሐፍት ከመጠባበቂያ ፋይል ይመልሱ ምትኬ ወደነበረበት diff --git a/i18n/src/main/res/values-ar/strings.xml b/i18n/src/main/res/values-ar/strings.xml index 7c03eb3a7..da4b33af0 100644 --- a/i18n/src/main/res/values-ar/strings.xml +++ b/i18n/src/main/res/values-ar/strings.xml @@ -133,9 +133,8 @@ إستعادة النسخة الإحتياطية إستعادة مكتبة من ملف نسخة إحتياطية موقع النسخ الإحتياطي - النسخ الاحتياطيّة التلقائيّة - معدل النسخ الإحتياطي - أقصى عدد للنسخ الاحتياطيّة + معدل النسخ الاحتياطي التلقائي + أقصى عدد للنسخ الاحتياطية التلقائية أُنشئت نسخة احتياطية اكتملت الاستعادة ما الذي تريد نسخه احتياطيّاً؟ @@ -154,10 +153,8 @@ تم محو ملفات تعريف الارتباط محو قاعدة البيانات مسح سجلّ الإدخالات التي ليست محفوظة في مكتبتك - أمتأكِّد؟ إن فعلتَ خسرتَ الفصول المقروءة وسير القراءة + أمتأكِّد؟ إن فعلتَ خسرتَ الفصول المقروءة و التقدم فى العنوانين الغير محفوظة فى المكتبة تم حذف المدخلات - تحديث بيانات التتبع - تحديث الحالة، والتقييم، وآخر فصل: عن طريق خدمات التتبع اﻹصدار إرسال تقارير الأعطال هذا يساعد فى حل أي مشاكل. لن يتم إرسال أيّة بيانات حساسة @@ -234,7 +231,7 @@ لا يتوفر اتصال واي فاي لا يتوفر اتصال بالشبكة توقفت التنزيلات - عامٌّ + عام نقل الإضافات معلومات الإضافة @@ -467,7 +464,7 @@ تاريخ الإضافة ما الجديد يتطلب إعادة تشغيل التطبيق ليتم تفعيله - شبكة الاتصال + التشبيك أجهزة التتبع التي لم يتم تسجيل الدخول إليها: حذف الفصول ذات العلامة المرجعية حذف الفصول @@ -530,7 +527,7 @@ الوضع المخفي مسح السجل الصفحة التالية - الصفحة سابقة + الصفحة السابقة دليل ترحيل المصدر محتوى +18 اعرض في قوائم المصادر والامتدادات @@ -597,8 +594,6 @@ تنسيق الفصل غير صالح تعليمات التعقب إعدادات فرز كل صنف - تحديث المتعقبات عند تحديث المكتبة - تحديث المتعقبات تلقائياً إلغاء الكل لهذه السلسلة مصدر محلّي ليس لديك اي قوائم بعد. @@ -687,7 +682,7 @@ فشل %1$d تحديث أو تحديثات تُخُطِّي %1$d تحديث أو تحديثات اضغط لقراءة المزيد - نسخة جديدة متاحة من الإصدارات الرسمية. انقر لمعرفة كيفية الهجرة من إصدارات F-Droid غير الرسمية. + نسخة جديدة متاحة من الإصدارات الرسمية. انقر لمعرفة كيفية التحويل من إصدارات F-Droid غير الرسمية. نقل سلسلة الفصول للأعلى لا توجد مدخلات في المكتبة لإجراء نسخة احتياطي‮‮ة اغلاق @@ -761,7 +756,7 @@ التحميل التلقائي، التحميل مقدما تزامن التقدم أحادي الاتجاه، مزامنة محسّنة المصادر، الامتدادات، البحث العالمي - النسخ الاحتياطي اليدوي والآلي + النسخ الاحتياطي اليدوي والآلي وحيِّز التخزين قفل التطبيق، شاشة آمنة تفريغ سجلات الأعطال وتحسينات البطارية لا يتم دعم إصدارات F-Droid رسميا. @@ -872,10 +867,10 @@ مرخَّصة - لا فصول ولوج المتتبِّع أُفسد فهرس التنزيلات - اضغط هنا تتحرَّ كلاودفلير + اضغط هنا للمساعدة فى Cloudflare لا اتصال بالإنترنت خطأ HTTP %d، انظر في WebView - لم نصل %s + لا يمكن الوصول إلى %s افتح %s انقل السلسلة للقعر التوقيت النسبي @@ -886,4 +881,5 @@ إعدادات المصادر إعدادات التطبيق ما استطاع محدِّد الملفات من إدخال الملف في التطبيق + البيانات والتخزين \ 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 fc1ec51dc..5dd7cc756 100644 --- a/i18n/src/main/res/values-b+es+419/strings.xml +++ b/i18n/src/main/res/values-b+es+419/strings.xml @@ -293,7 +293,6 @@ Copia de seguridad creada Máximo de copias de seguridad Frecuencia de respaldo - Copias de seguridad automáticas Directorio de copia de seguridad Restaurar biblioteca desde archivo de copia de seguridad Caché borrada. %1$d archivos se han eliminado @@ -305,8 +304,6 @@ La optimización de la batería ya está desactivada Ayuda con las actualizaciones y las copias de seguridad de biblioteca en segundo plano Desactivar optimización de batería - Actualizar estado, puntuación y último capítulo leído en los servicios de seguimiento - Refrescar seguimiento Actualizar portadas de la biblioteca Entradas eliminadas ¿Estas seguro\? Los capítulos leídos y el progreso del manga que no estén en la biblioteca se perderán @@ -585,8 +582,6 @@ Desactivado Activado Si la partición de la página ancha no coincide con la dirección de lectura - Actualizar rastreadores al actualizar la biblioteca - Actualizar rastreadores automáticamente Restricciones: %s Ayer @@ -623,7 +618,7 @@ Actualizar todo Solo con Wi-Fi Política de privacidad - Deberías tener copias de seguridad guardadas en otros sitios también. + Deberías tener copias de seguridad guardadas en otros sitios también. Las copias de seguridad pueden contener datos sensibles incluyendo contraseñas guardadas; tenga cuidado si lo comparte. Publicación terminada Cancelado En hiatus @@ -834,7 +829,8 @@ \"%1$s\" en lugar de \"%2$s\" Ordenar categorías Actualizando biblioteca… (%s) - Categorías + ¿Quieres ordenar las categorías de forma alfabética\? Configuraciónes de fuente Configuraciones + El selector de archivos no pudo devolver el archivo a la aplicación \ 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 0a9ac827b..8caa4e85f 100644 --- a/i18n/src/main/res/values-be/strings.xml +++ b/i18n/src/main/res/values-be/strings.xml @@ -113,8 +113,6 @@ Налады для кожнай катэгорыі для сартавання і адлюстравання Заўсёды пытацца Катэгорыя па змаўчанні - Абнаўляць адсочванне пры абнаўленні бібліятэкі - Аўтаматычна абнаўляць адсочванне Правераць наяўнасць новай вокладкі і дэталяў пры абнаўленні бібліятэкі Аўтаматычнае абнаўленне метададзеных Абнаўляць толькі незавершаную мангу diff --git a/i18n/src/main/res/values-bg/strings.xml b/i18n/src/main/res/values-bg/strings.xml index 6154d960c..0491ef282 100644 --- a/i18n/src/main/res/values-bg/strings.xml +++ b/i18n/src/main/res/values-bg/strings.xml @@ -249,7 +249,6 @@ Възстанови резервно копие Възстанови библиотеката от резервно копие Директория за резервното копие - Автоматично запазване Честота на запазване Максимален брой копия Резервно копие създадено @@ -257,8 +256,6 @@ Какво искате да запазите? Възстановяване на копие Създаване на резервно копие - Обнови проследяването - Обновява статус, оценка и последно прочетена глава от услугите за проследяване Локални Да се изтрият ли изтеглените глави? На пауза @@ -540,7 +537,6 @@ L-образно Kindle-подобно Автоматично - Обновявай тракерите при обновявания на библиотеката Схема на навигацията Преди След @@ -574,7 +570,6 @@ Ин и Янг Йоцуба Ограничения: %s - Автоматично обновявай тракерите Различно сортиране и показване за всяка категоря Манга в изключените категории няма да бъде обновявана дори ако се намира във включените категории. Никоя diff --git a/i18n/src/main/res/values-bn/strings.xml b/i18n/src/main/res/values-bn/strings.xml index f785b679d..1cbf20edd 100644 --- a/i18n/src/main/res/values-bn/strings.xml +++ b/i18n/src/main/res/values-bn/strings.xml @@ -139,7 +139,6 @@ ব্যাকআপ পুনরুদ্ধার ব্যাকআপ ফাইল থেকে সংগ্রহশালা পুনরুদ্ধার করুন ব্যাকআপের স্থান - স্বয়ংক্রিয় ব্যাকআপ ব্যাকআপ ফ্রিকোয়েন্সি সর্বোচ্চ ব্যাকআপ ব্যাকআপ তৈরী হয়েছে @@ -157,8 +156,6 @@ আপনার সংগ্রহশালাতে যেসব মাংগা সংরক্ষিত নেই সেগুলোর ইতিহাস মুছে ফেলুন আপনি কি নিশ্চিত\? পঠিত অধ্যায় এবং সংগ্রহশালাতে অনুপস্থিত মাংগার অগ্রগতি মুছে যাবে এন্ট্রিগুলো মুছে ফেলা হয়েছে - ট্র্যাকিং হালনাগাদ করুন - ট্র্যাকিং পরিষেবাগুলি অবস্থা, স্কোর এবং শেষ পড়া অধ্যায় হালনাগাদ করে সংস্করণ ক্র‍্যাশের প্রতিবেদন পাঠান বাগ ঠিক করার জন্য সাহায্য করুন। কোন সংবেদনশীল তথ্য পাঠানো হবে না @@ -561,8 +558,6 @@ শূন্য বাদ দেওয়া ক্যাটাগরিতে মঙ্গা আপডেট করা হবে না যদিও সেগুলি অন্তর্ভুক্ত ক্যাটাগরিতেও থাকে। সাজানোর এবং প্রদর্শনের জন্য প্রতি শ্রেণীর সেটিংস - লাইব্রেরি আপডেট করার সময় ট্র্যাকার আপডেট করুন - স্বয়ংক্রিয়ভাবে রিফ্রেশ ট্র্যাকার বিধিনিষেধ: %s গতকাল diff --git a/i18n/src/main/res/values-ca/strings.xml b/i18n/src/main/res/values-ca/strings.xml index 45b2684c3..6a88ec38b 100644 --- a/i18n/src/main/res/values-ca/strings.xml +++ b/i18n/src/main/res/values-ca/strings.xml @@ -162,7 +162,6 @@ Restaura una còpia de seguretat Restaura la biblioteca del fitxer de còpia de seguretat Ubicació de la còpia de seguretat - Còpies de seguretat automàtiques Freqüència de la còpia de seguretat Màxim de còpies de seguretat S’ha creat la còpia de seguretat @@ -180,8 +179,6 @@ Suprimeix l’historial dels elements que no siguin a la biblioteca N’esteu segur\? Es perdrà el progrés i els capítols llegits dels elements que no siguin a la biblioteca S’han suprimit les entrades - Refresca el seguiment - Actualitza l’estat, la puntuació i el darrer capítol llegit dels serveis de seguiment Versió Envia informes d’errors Ajuda a solucionar errades. No s’enviaran dades sensibles @@ -544,8 +541,6 @@ Data Ordena per El format del capítol no és vàlid - Actualitza els serveis de seguiment en actualitzar la biblioteca - Actualitza automàticament els serveis de seguiment No s’ha trobat el capítol S’ha produït un error en compartir la portada S’ha produït un error en desar la portada @@ -821,4 +816,5 @@ Voleu ordenar les categories alfabèticament\? Configuració de la font Configuració de l’aplicació + El selector de fitxers no ha retornat cap fitxer a l’aplicació \ 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 aaa60ccf4..03d06c1b0 100644 --- a/i18n/src/main/res/values-ceb/strings.xml +++ b/i18n/src/main/res/values-ceb/strings.xml @@ -192,8 +192,6 @@ Awtomatikong pag-update sa mga pagdili sa device Sa Wi-Fi lang Uban sa \"Nakumpleto\" nga kahimtang - Pag-update sa mga tracker kung nag-update sa librarya - Awtomatikong i-refresh ang mga tracker Default nga kategorya Kada 3 ka adlaw Susiha ang bag-ong hapin ug mga detalye kung mag-update sa librarya @@ -387,7 +385,6 @@ \nKinahanglan nimo nga i-install ang bisan unsang nawala nga mga extension ug mag-log in sa mga serbisyo sa pagsubay pagkahuman aron magamit kini. Nakompleto ang pag-uli Paghimo og backup - Awtomatikong pag-backup Ang mga tracker wala naka-log in: Nabuhat sa %1$s nga adunay %2$s nga sayup @@ -408,7 +405,6 @@ Gigamit: %1$s Limpyo ang database I-refresh ang mga hapin sa librarya - Mga update sa status, score ug katapusang kapitulo nga gibasa gikan sa mga serbisyo sa pagsubay Dump crash logs I-print ang verbose logs ngadto sa system log (gipamenos ang performance sa app) Ang ubang mga tiggama adunay dugang nga mga pagdili sa app nga nagpatay sa mga serbisyo sa background. Kini nga website adunay dugang nga impormasyon kon unsaon kini pag-ayo. @@ -430,7 +426,6 @@ Gitangtang ang mga entry Tin-aw ang datos sa WebView Ang datos sa WebView gitangtang - I-refresh ang pagsubay I-reset ang mga setting sa matag-serye nga magbabasa I-reset ang mode sa pagbasa ug oryentasyon sa tanan nga serye Ang tanan nga mga setting sa magbabasa gi-reset diff --git a/i18n/src/main/res/values-cs/strings.xml b/i18n/src/main/res/values-cs/strings.xml index 10f2a3842..74873157e 100644 --- a/i18n/src/main/res/values-cs/strings.xml +++ b/i18n/src/main/res/values-cs/strings.xml @@ -208,7 +208,6 @@ Vytvořit zálohu Obnovit zálohu Místo zálohy - Automatické zálohy Frekvence zálohy Záloha vytvořena Obnova dokončena @@ -225,8 +224,6 @@ Smazat historii položek, které nejsou uloženy ve vaší knihovně Jste si jistí\? Přečtené kapitoly a postup v položkách mimo knihovnu bude ztracen Položky byly smazány - Obnovit sledování - Aktualizuje status, skóre a poslední přečtenou kapitolu ze sledovacích služeb Verze Odesílat hlášení o pádu Pomáhá opravit chyby. Nebudou odeslány žádné citlivé údaje @@ -554,8 +551,6 @@ Seřadit podle Neplatný formát kapitoly Kapitola nenalezena - Aktualizovat sledovače při aktualizaci knihovny - Automaticky aktualizovat sledovače Omezení: %s Lokální zdroj Při sdílení přebalu došlo k chybě diff --git a/i18n/src/main/res/values-cv/strings.xml b/i18n/src/main/res/values-cv/strings.xml index ff432c11b..65ffa0e9e 100644 --- a/i18n/src/main/res/values-cv/strings.xml +++ b/i18n/src/main/res/values-cv/strings.xml @@ -261,8 +261,6 @@ Сӑнану хуш Сӑна - Сӑнану сервиссенчен халне, шутне тата юлашки вуланӑ сыпӑка илсе ҫӗнет - Сӑнанӑва ҫӗнет Усӑҫ али Кирек мӗнле йӑнӑшсене тӳрлетме пулӑшать. Нимӗнле харкам пӗлӗм те ярӑнмасть Тиенӗсене ҫеҫ @@ -440,7 +438,6 @@ Янтӑвра манкӑсем ҫук. Янтӑв тӑвӑннӑ Май килнӗ таран янтӑвсем - Хӑй-халлӗн янтӑвлани Янтӑв вырнаҫни Вулавӑша янтӑвран тавӑр Янтӑв тавӑр @@ -600,7 +597,6 @@ Хӑй-хальлӗн Сӳнтернӗ Хушмасен йат-йышне илесси пулаймарӗ - Вулавӑша ҫӗнетнӗ май йӗрлеве те ҫӗнетни Кашни пухмӑшӑн хӑйӗн ала ӗнерӗвӗсем Ап ҫинчен Вулӑшӑн тухӑҫа лайӑхлатать @@ -610,7 +606,6 @@ Вӑрӑм сӑнсене пайлани Управ ирӗкӗсене паман Версси - Йӗрлеве хӑй-хальлӗн ҫӗнетни Пурне те ҫӗнет Тийесе илнисене катерт Ретре %d diff --git a/i18n/src/main/res/values-da/strings.xml b/i18n/src/main/res/values-da/strings.xml index ccd1e3144..dadb6345c 100644 --- a/i18n/src/main/res/values-da/strings.xml +++ b/i18n/src/main/res/values-da/strings.xml @@ -191,7 +191,6 @@ Standard kategori Nyeste manga opdateringer Antal ulæst - Opdater automatisk trackere Slet kategori %d kategori @@ -199,7 +198,6 @@ Ekskluder: %s Lavendel - Opdater trackere når biblioteket opdateres Spørg altid Manga i ekskluderede kategorier vil ikke blive opdateret selv hvis de også er i inkluderede kategorier. Alle diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml index 98eef49ce..560b38339 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -135,7 +135,6 @@ Datensicherung wiederherstellen Bibliothek mit Hilfe einer Datensicherung wiederherstellen Sicherungsspeicherort - Automatische Datensicherungen Datensicherungshäufigkeit Maximale Datensicherungen Datensicherung erstellt @@ -153,8 +152,6 @@ Verlauf für Einträge löschen, die nicht in deiner Bibliothek gespeichert sind Bist du dir sicher\? Die gelesenen Kapitel und Fortschritte von Einträgen, die nicht in deiner Bibliothek sind, werden gelöscht Einträge gelöscht - Tracking aktualisieren - Synchronisiert den Lesestatus, die Bewertung und das zuletzt gelesene Kapitel mit den angemeldeten Trackinganbietern Version Fehlerberichte senden Hilft bei der Behebung von Fehlern. Keine sensiblen Daten werden gesendet @@ -545,8 +542,6 @@ Sortiere nach Ungültiges Kapitelformat Kapitel nicht gefunden - Tracker aktualisieren, wenn die Bibliothek aktualisiert wird - Tracker automatisch aktualisieren Einschränkungen: %s Lokale Quelle Aus @@ -605,7 +600,7 @@ Sprache Warnung Große Aktualisierungen schaden Quellen und könnten zu langsameren Aktualisierungen sowie höherem Akkuverbrauch führen. Tippe, um mehr zu erfahren. - Du solltest auch Kopien der Sicherungen an anderen Orten aufbewahren. Sicherungen beinhalten möglicherweise sensible Daten, einschließlich jeglicher gespeicherten Passwörter. Vorsicht beim Teilen. + Du solltest Kopien der Sicherungen auch an anderen Orten aufbewahren. Sicherungen beinhalten möglicherweise sensible Daten, einschließlich gespeicherter Passwörter. Sei vorsichtig beim Teilen. Nur über WLAN Alle 3 Tage Achtung: Große Downloads könnten dazu führen, dass Quellen langsamer werden und/oder Tachiyomi blockieren. Tippe, um mehr zu erfahren. @@ -821,4 +816,5 @@ Bibliothek wird aktualisiert… (%s) Kategorien sortieren Möchtest du die Kategorien alphabetisch sortieren\? + Dateiauswahl konnte keine Datei an die App zurückgeben \ 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 adbd9ac75..520d78f1f 100644 --- a/i18n/src/main/res/values-el/strings.xml +++ b/i18n/src/main/res/values-el/strings.xml @@ -162,7 +162,6 @@ Επαναφορά αντιγράφου ασφαλείας Επαναφορά βιβλιοθήκης από αρχείο αντιγράφου ασφαλείας Τοποθεσία αντιγράφων ασφαλείας - Αυτόματα αντίγραφα ασφαλείας Συχνότητα αντίγραφου ασφάλειας Μέγιστα αντίγραφα ασφαλείας Δημιουργήθηκε αντίγραφο ασφαλείας @@ -180,8 +179,6 @@ Διαγραφή ιστορικού για καταχωρήσεις που δεν έχουν αποθηκευτεί στη βιβλιοθήκη σας Είστε σίγουροι; Τα διαβασμένα κεφάλαια και η πρόοδος των καταχωρήσεων εκτός βιβλιοθήκης θα χαθούν Οι καταχωρίσεις διαγράφηκαν - Ανανέωση tracking - Ενημερώνει κατάσταση, βαθμολογία και τελευταίο αναγνωσμένο κεφάλαιο από τις υπηρεσίες παρακολούθησης Έκδοση Αποστολή αναφορών σφαλμάτων Βοηθά στην επιδιόρθωση τυχόν σφαλμάτων. Δεν θα αποστέλλονται ευαίσθητα δεδομένα @@ -543,8 +540,6 @@ Αδιάβαστα Ημερομηνία Ταξινόμηση κατά - Ενημέρωση των trackers κατά την ενημέρωση της βιβλιοθήκης - Αυτόματη ανανέωση των trackers Μη έγκυρη μορφή κεφαλαίου Το κεφάλαιο δε βρέθηκε Περιορισμοί: %s @@ -821,4 +816,5 @@ Ενημέρωση βιβλιοθήκης… (%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 d3f4f8a2c..ae6ffee77 100644 --- a/i18n/src/main/res/values-eo/strings.xml +++ b/i18n/src/main/res/values-eo/strings.xml @@ -364,7 +364,6 @@ %02d min, %02d sek Mankantaj fontoj: - Aŭtomataj savkopioj Aŭtomata elŝuto Laste legita ĉapitro Orientiĝa speco @@ -461,8 +460,6 @@ Du-paĝa divido Ĉi tiu kromaĵo ne estas de la oficiala Tachiyomi kromaĵlisto. Atendantaj - Aktualigi ŝanĝspurilojn kiam ĝisdatigi bibliotekon - Aŭtomate aktualigi ŝanĝspurilojn Nur ĝisdatigi okazantaj mangaojn Limigoj: %s Jotsuba @@ -477,7 +474,6 @@ Aktualigi limigojn Findato Komencdato - Aktualigi ŝanĝspuradon Ŝanĝspuriloj ne ensalutintaj al: Ŝanĝspurata Animi transpaso de paĝoj diff --git a/i18n/src/main/res/values-es/strings.xml b/i18n/src/main/res/values-es/strings.xml index 77b438159..e9062da65 100644 --- a/i18n/src/main/res/values-es/strings.xml +++ b/i18n/src/main/res/values-es/strings.xml @@ -74,8 +74,8 @@ Blanco Negro Sentido de lectura normal - Por páginas, de izquierda a derecha - Páginas (de derecha a izquierda) + Por páginas (de izquierda a derecha) + Por páginas (de derecha a izquierda) Por páginas, de arriba abajo Tira vertical continua Método de ampliación @@ -237,7 +237,6 @@ Restaurar copia de seguridad Restaurar la biblioteca a partir de una copia de seguridad Ubicación de la copia de respaldo - Copias de seguridad automáticas Frecuencia de respaldo Copias de seguridad máximas Copia de seguridad creada @@ -245,8 +244,6 @@ ¿De qué quieres hacer una copia de seguridad\? Restaurando copia de seguridad Creando copia de seguridad - Descargar datos actualizados de seguimiento - Actualiza estados, puntuaciones y últimos capítulos leídos desde tus servicios de seguimiento No hay más resultados Fuente local ¿Eliminar los capítulos descargados\? @@ -612,8 +609,6 @@ No Establecer el tipo de orden para cada categoría - También intenta actualizar el historial de lectura al actualizar la biblioteca - Sincronizar automáticamente los datos en servicios de seguimiento Actividad en segundo plano Seguir Guía de introducción @@ -819,7 +814,7 @@ Girar las páginas anchas para adaptarlas a la pantalla Girar las páginas anchas en la dirección opuesta - Información de depuración + Información sobre la depuración Deslizamiento de dedo en capítulos Deslizar a la izquierda Deslizar a la derecha @@ -868,4 +863,5 @@ Ajustes de la aplicación Ordenar categorías ¿Quieres ordenar las categorías de forma alfabética\? + La pantalla de selección de archivos no ha devuelto ningún archivo \ 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 439ccd799..4cef824bb 100644 --- a/i18n/src/main/res/values-eu/strings.xml +++ b/i18n/src/main/res/values-eu/strings.xml @@ -200,7 +200,6 @@ Zaharkitua Desinstalatu Erakutsi orrialdearen zenbakia - Freskatu jarraipena Liburutegian Gehiago %1$s Kapitulua @@ -474,7 +473,6 @@ Babeskopia erabili Berreskuratu liburutegia babeskopia fitxategitik Babeskopiaren kokapena - Babeskopia automatikoak Babeskopien maiztasuna Gehienezko babeskopiak Alfabetikoki @@ -543,8 +541,6 @@ Mugaketak: %s Argitalpen bukatua al da Freskatu metadatuak automatikoki - Freskatu jarraitzaileak automatikoki - Eguneratu jarraitzaileak liburutegia eguneratzean Babeskopiak ez du mangarik. Jarraipena Berrirakurtzen @@ -606,7 +602,6 @@ Bertan behera utzia Etenaldian Liburutegi eguneraketen akatsak nola konpondu jakiteko, ikusi %1$s - Egoera, puntuaketa eta azken kapitulu irakurria eguneratzen ditu jarraipen-zerbitzuetatik Manga lokala %1$s kapituluak eta bat gehiago diff --git a/i18n/src/main/res/values-fa/strings.xml b/i18n/src/main/res/values-fa/strings.xml index 4ea639591..bddb1ba85 100644 --- a/i18n/src/main/res/values-fa/strings.xml +++ b/i18n/src/main/res/values-fa/strings.xml @@ -89,8 +89,6 @@ به کتابخانه اضافه شد حذف از کتابخانه در کتابخانه - وضعیت خواندن، امتیاز و آخرین قسمت خوانده شده را از سایت خدمات ردیابی آپدیت می‌کند - تازه کردن ردیابی برای به روز رسانی وضعیت پیشرفت قسمت ها، در سایت های خدمات ردیابی، همگام سازی یک طرفه انجام دهید. برای ردیابی هر داده از تب ردیابی اقدام کنید. وب تون(Webtoon) Burn / Darken @@ -132,7 +130,6 @@ تب ها حداکثر تعداد نسخه‌های پشتیبان زمان پشتیبان گیری - پشتیبان گیری خودکار محل پشتیبان گیری بازگرداندن کتابخانه از فایل پشتیبان برگرداندن نسخه پشتیبان @@ -553,12 +550,10 @@ %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 d5464ff55..7d0192a04 100644 --- a/i18n/src/main/res/values-fi/strings.xml +++ b/i18n/src/main/res/values-fi/strings.xml @@ -206,7 +206,6 @@ Palvelut Voidaan käyttää nykyisen kirjaston palauttamiseen Palauta kirjasto varmuuskopiointi-tiedostosta - Automaattiset varmuuskopiot Varmuuskopioinnin tiheys Varmuuskopioiden enimmäismäärä Varmuuskopio luotu @@ -224,8 +223,6 @@ Poista mangan historia, jota ei ole tallennettu kirjastoosi Oletko varma\? Luetut luvut ja eteneminen poistetaan muista kun kirjastossa olevista sarjoista Tiedot poistettu - Päivitä seuranta - Päivittää tilan, arvosanan ja viimeksi luetun luvun seurantapalveluista Versio Lähetä kaatumisilmoituksia Auttaa korjaamaan bugeja. Arkaluonteista tietoa ei lähetetä @@ -549,7 +546,6 @@ Päällä 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 @@ -560,7 +556,6 @@ Vihreä omena Oletus Laitteelle tallennettu manga - Päivitä seurantapalvelimet automaattisesti Yhteenlaskettu manga Aloita lataaminen nyt Ying ja Yang diff --git a/i18n/src/main/res/values-fil/strings.xml b/i18n/src/main/res/values-fil/strings.xml index c5d86d185..75437dcaf 100644 --- a/i18n/src/main/res/values-fil/strings.xml +++ b/i18n/src/main/res/values-fil/strings.xml @@ -239,8 +239,7 @@ Nai-backup na Dami ng backup Dalas ng pag-backup - Kusang mag-backup - Lugar ng backup + Lokasyon ng backup I-restore ang Aklatan mula sa backup I-restore ang backup Magagamit para ma-restore ang kasalukuyang Aklatan @@ -422,8 +421,6 @@ Nakapatay na ang pag-o-optimisa sa baterya Patayin ang pag-o-optimisa sa baterya Nakatutulong sa pag-update ng aklatan sa background at pag-backup - Inia-update ang estado, iskor, at huling nabasang kabanata mula sa mga tracker - Sariwain ang pagta-track I-refresh ang mga cover sa aklatan Binura na Sigurado ka ba\? Ang mga nabasang kabanata at pag-unlad ng mga wala sa aklatan ay mawawala @@ -538,8 +535,6 @@ Isara ang incognito Kusa Ikansela lahat para sa seryeng ito - I-update ang tracker tuwing nag-a-update ang Aklatan - Kusang sariwain ang tracker Ayusin ayon sa Restriksyon: %s Walang nahanap na kapares @@ -822,4 +817,5 @@ Mga setting ng source Mga setting ng app Ang file picker ay nabigo na ibalik ang file sa app + Data at storage \ 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 2c0388300..1bb270c1c 100644 --- a/i18n/src/main/res/values-fr/strings.xml +++ b/i18n/src/main/res/values-fr/strings.xml @@ -243,7 +243,6 @@ Ouvrir le fichier Restaurer Dossier de sauvegarde - Sauvegardes automatiques Restauration terminée Que voulez-vous sauvegarder \? Supprimer les chapitres téléchargés ? @@ -258,8 +257,6 @@ Sauvegarde créée Restauration de sauvegarde en cours Création de sauvegarde en cours - Actualiser les métadonnées de suivi - Actualise le statut, la note et le dernier chapitre lu depuis les services de suivi Toujours demander Inverser les boutons de volume Rogner les bordures @@ -589,8 +586,6 @@ Chapitre non trouvé Rotation Auto - Mettre à jour les services de suivi lors de la mise à jour de la bibliothèque - Actualiser automatiquement les services de suivi Restrictions : %s Tout annuler pour cette série Source locale diff --git a/i18n/src/main/res/values-gl/strings.xml b/i18n/src/main/res/values-gl/strings.xml index a325d1886..9a7ef4d40 100644 --- a/i18n/src/main/res/values-gl/strings.xml +++ b/i18n/src/main/res/values-gl/strings.xml @@ -317,7 +317,6 @@ O axente de usuario non pode estar vacío Usado: %1$s Borrar a caché dos capítulos ao pechar a aplicación - Actualizar o estado, as puntuacións e os últimos capítulos lidos dende os servizos de seguemento Non se puideron abrir os axustes do dispositivo Enviar informes de erros Lapelas @@ -382,7 +381,6 @@ Servizos mellorados Estes servizos proporcionan funcións melloradas para fontes concretas. Faise un seguemento automático dos elementos ao engadilos á biblioteca. Localización da copia de seguridade - Copias de seguridade automáticas Xa se está facendo unha copia de seguridade Compartir os rexistros de erros Error ao compartir a portada @@ -422,7 +420,6 @@ Non hai nada que borrar Borrar os datos do WebView Restablecer o modo de lectura e a orientación de tódalas series - Actualizar o seguemento Número de non lidos Mostrar o elemento Data de obtención dos capítulos @@ -450,8 +447,6 @@ Azul mariño e turquesa Yin e Yang Modo negro puro - Actualizar automaticamente os servizos de seguemento - Actualizar os servizos de seguemento ao actualizar a biblioteca Incluír: %s Non se puido baixar a listaxe de extensións Borrar a base de datos diff --git a/i18n/src/main/res/values-he/strings.xml b/i18n/src/main/res/values-he/strings.xml index 4ab6a008a..bcdcf1d3c 100644 --- a/i18n/src/main/res/values-he/strings.xml +++ b/i18n/src/main/res/values-he/strings.xml @@ -221,7 +221,6 @@ אופטימיזציית סוללה כבר מושבתת עוזר בעדכוני ספריות רקע וגיבויים השבתת האופטימיזציה של הסוללה - עדכן סטטוס, ציון ופרק אחרון שנקרא משירותי המעקב הרשומות נמחקו האם אתה בטוח\? פרקים שנקראו וההתקדמות של פריטים שאינם בספרייה יאבדו מחק את היסטוריית הפריטים שאינם שמורים בספריה שלך @@ -239,7 +238,6 @@ גיבוי נוצר מספר גיבויים מקסימלי תדירות גיבוי - גיבויים אוטומטיים מיקום גיבוי שחזר ספרייה מקובץ גיבוי שחזור גיבוי @@ -349,7 +347,6 @@ שום דבר לא נקרא לאחרונה אין עידכונים אחרונים סומן - רענון עוקבים אוטומטית ברירת המחדל ערכת הנושא של האפליקציה התחל להוריד עכשיו @@ -381,7 +378,6 @@ זה לא מונע תוספים לא רשמיים או תוספים שעלולים לסמן באופן שגוי מלהציג תוכן NSFW (18+) בתוך האפליקציה. היום תצוגה - עדכן עוקבים בעת עדכון הספרייה אפשר הכל השבת הכל התחל @@ -779,7 +775,6 @@ קבע גם עבור כל הפריטים בספריה רק ברשת בלתי מוגבלת שתף יומני קריסה - רענן מעקבים פעולה זו תסיר את תאריך ההתחלה הקודם שלך מ-%s רשימת קריאה רשימת תכנונים diff --git a/i18n/src/main/res/values-hi/strings.xml b/i18n/src/main/res/values-hi/strings.xml index 2a89cff93..cb62abed9 100644 --- a/i18n/src/main/res/values-hi/strings.xml +++ b/i18n/src/main/res/values-hi/strings.xml @@ -139,7 +139,6 @@ बैकअप पुनर्स्थापित करे बैकअप फ़ाइल से लाइब्रेरी पुनर्स्थापित करें बैकअप निर्देशिका - स्वचालित बैकअप बैकअप फ़्रीक्वेंसी अधिकतम बैकअप बैकअप बनाया गया है @@ -157,8 +156,6 @@ उन आइटम का इतिहास हटाएं जो आपकी पुस्तकालय में सहेजी नहीं गई हैं क्या आपको यकीन है\? आपके द्वारा पढ़े गए अध्याय और गैर-पुस्तकालय आइटम की प्रगति खो जाएगी प्रविष्टियां हटाई गईं - रिफ्रेश ट्रैकिंग - अपडेट की स्थिति, स्कोर और अंतिम अध्याय ट्रैकिंग सेवाओं से पढ़ें संस्करण क्रैश रिपोर्ट भेजें किसी भी बग को ठीक करने में मदद करता है कोई संवेदनशील डेटा नहीं भेजा जाएगा @@ -528,7 +525,6 @@ यीन और यैंन्ग टील रूप - ट्रैकर्स को स्वचालित रूप से रीफ्रेश करें कोई नहीं बहिष्कृत करें: %s बंद @@ -560,7 +556,6 @@ कुल आइटम मिडनाइट डस्क आज - पुस्तकालय अपडेट करते समय ट्रैकर्स को अपडेट करें शामिल करें: %s ऐप की जानकारी शिज़ुकु नहीं चल रहा है diff --git a/i18n/src/main/res/values-hr/strings.xml b/i18n/src/main/res/values-hr/strings.xml index 6beb4859d..15b468ea9 100644 --- a/i18n/src/main/res/values-hr/strings.xml +++ b/i18n/src/main/res/values-hr/strings.xml @@ -159,8 +159,7 @@ Obnavljanje je završeno Sigurnosna kopija je stvorena Maksimalni broj sigurnosnih kopija - Učestalost spremanja sigurnosnih kopija - Automatsko spremanje sigurnosnih kopija + Učestalost automatskog spremanja sigurnosnih kopija Mjesto spremanja sigurnosnih kopija Obnovi biblioteku iz sigurnosne kopije Obnovi sigurnosnu kopiju @@ -370,8 +369,6 @@ Optimiranje baterije je već isključeno Pomaže pri ažuriranju biblioteke u pozadini i spremanju sigurnosnih kopija Deaktiviraj optimiranje baterije - Aktualizira stanje, ocjenu i zadnje pročitano poglavlje iz usluga za praćenje - Aktualiziraj praćenje Unosi su izbrisani Sigurno\? Pročitana poglavlja i tijek unosa koji nisu u biblioteci će se izgubiti Izbriši povijest za unose koji nisu spremljeni u biblioteci @@ -446,7 +443,7 @@ %1$s poglavlja Zahtijeva ponovno pokretanje programa - Mreža + Umreženi rad Oboje Okomito Vodoravno @@ -566,8 +563,6 @@ Isključeno Uključeno Postavke kategorija za sortiranje - 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. @@ -693,7 +688,7 @@ Lokalno Traži … Kategorije, globalno ažuriranje, prelistavanje poglavlja - Ručne i automatske sigurnosne kopije + Ručne i automatske sigurnosne kopije, memorija Statistike Preuzeto Gumb za nastavljanje čitanja @@ -788,7 +783,7 @@ Prilagodi prikaz širokih stranica okretanjem Preokreni položaj širokih stranica - Informacije otklanjanja grešaka + Informacije o otklanjanju grešaka %d po retku Prelistaj ulijevo Dodirni dvaput za zumiranje @@ -838,4 +833,5 @@ Program za biranje datoteka nije uspio vratiti datoteku u aplikaciju Postavke izvora Postavke aplikacije + Podaci i spremište \ 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 b07be9770..57406f7da 100644 --- a/i18n/src/main/res/values-hu/strings.xml +++ b/i18n/src/main/res/values-hu/strings.xml @@ -334,8 +334,6 @@ Érintési zónák átfedésének mutatása Alkalmazás információ Kategóriakénti beállítások rendezéshez - Követők frissítése könyvtár frissítésekor - Követők automatikus frissítése Polip Eper koktél @@ -503,7 +501,6 @@ \nEzek után telepíteni kell a hiányzó bővítményeket és be kell jelentkezni a tracking szolgáltatásokba, hogy újra használhassa őket. Könyvtár fedők frissítése Hibaüzenetetek törlése - Frissíti az állapotot, értékelést és az utolsó olvasott fejezetet a tracking szolgáltatás által Sorozat beállításainak visszaállítása Néhány gyártónak extra korlátozása van arra, hogy kikapcsolja a háttér folyamatokat. Ezen a web oldalon több információt találsz, hogy hogyan oldható meg. Olvasási előzmények megállítása @@ -513,7 +510,6 @@ Válasszon képet a fedlapnak Nem található új frissítés Kihagyott - Tracking frissítése Verzió Nyelv Korhatár @@ -639,7 +635,6 @@ Felhasználható az aktuális könyvtár visszaállítására Biztonsági mentés visszaállítása Könyvtár visszaállítása biztonsági mentésről - Automatikus biztonsági mentések Biztonsági mentések gyakorisága Befejezve %1$s alatt, %2$s hibával diff --git a/i18n/src/main/res/values-in/strings.xml b/i18n/src/main/res/values-in/strings.xml index a83de2d60..989ee6731 100644 --- a/i18n/src/main/res/values-in/strings.xml +++ b/i18n/src/main/res/values-in/strings.xml @@ -135,7 +135,6 @@ Pulihkan cadangan Pulihkan isi pustaka dari berkas cadangan Tempat pencadangan - Pencadangan otomatis Frekuensi cadangan dibuat Jumlah maksimum cadangan Cadangan dibuat @@ -151,10 +150,8 @@ Cookies dihapus Hapus database Hapus riwayat untuk entri yang tidak disimpan di perpustakaan Anda - Apa kamu yakin\? Baca bab dan kemajuan entri non-perpustakaan akan hilang + Apakah Anda yakin\? Bab yang sudah dibaca dan kemajuan entri non-perpustakaan akan hilang Entri dihapus - Segarkan pelacakan metadata - Perbarui status, nilai dan bab terakhir yang dibaca dari layanan pelacakan Versi Kirim laporan kerusakan Bantu memperbaiki bug. Tidak ada data sensitif yang akan dikirim @@ -532,8 +529,6 @@ Jika penempatan halaman lebar terpisah tidak sesuai dengan arah membaca Balikkan penempatan halaman pemisah Tunjukkan secara singkat saat pembaca dibuka - Perbarui pelacak ketika memperbarui pustaka - Segarkan pelacak secara otomatis Batasan: %s Sumber lokal Gagal berbagi sampul @@ -559,7 +554,7 @@ Hijau Apel Dinamis Tema aplikasi - Aktivitas dibelakang layar + Aktivitas latar belakang Terendah Rendah Sensitivitas untuk menyembunyikan menu dalam gulir @@ -590,7 +585,7 @@ Peringatan: mengunduh dalam jumlah besar bisa menyebabkan sumber menjadi lambat dan/atau memblokir Tachiyomi. Ketuk untuk mempelajari lebih lanjut. Peringatan Cetak catatan berlebih ke catatan sistem (mengurangi kinerja aplikasi) - Anda juga harus menyimpan salinan cadangan di tempat lain. + Anda juga harus menyimpan salinan cadangan di tempat lain. Cadangan mungkin berisi data sensitif termasuk kata sandi yang tersimpan; berhati-hatilah jika berbagi. Pencatatan berlebihan Filter warna kustom Atur kecerahan @@ -800,4 +795,10 @@ Pindahkan seri ke bawah Penanda waktu \"%1$s\" seharusnya \"%2$s\" + Mengurutkan kategori + Memperbarui pustaka... (%s) + Apakah Anda ingin mengurutkan kategori menurut abjad\? + Pemilih file gagal mengembalikan file ke aplikasi + Pengaturan sumber + Pengaturan aplikasi \ 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 4c63d836a..210e03ed4 100644 --- a/i18n/src/main/res/values-it/strings.xml +++ b/i18n/src/main/res/values-it/strings.xml @@ -247,12 +247,9 @@ Massimo numero di backup Backup creato Ripristino completato - Backup automatici Di cosa vuoi fare il backup\? Ripristino backup Creazione backup - Aggiorna tracking - Aggiorna stato, voto e ultimo capitolo letto dal servizio di tracking Nessun altro risultato Fonte locale Eliminare i capitoli scaricati? @@ -600,8 +597,6 @@ Copertina Formato capitolo non valido Guida al tracking - Aggiorna i tracker all\'aggiornarsi della libreria - Aggiorna automaticamente i tracker Inizia a scaricare ora Alcuni produttori hanno restrizioni aggiuntive per le app che chiudono i servizi in secondo piano. Questo sito ha più informazioni su come risolvere il problema. Più basso @@ -628,7 +623,7 @@ Tema applicazione Autenticarsi per confermare le modifiche Predefinita - Attività in secondo piano + Attività in background Le funzioni di backup e ripristino potrebbero non funzionare correttamente se le ottimizzazioni MIUI sono disabilitate. Offrono funzioni migliorate per fonti specifiche. Le voci sono tracciate automaticamente quando aggiunte alla libreria. Servizi di tracking migliorati @@ -870,4 +865,5 @@ Aggiornando libreria... (%s) Ordinamento categorie Vuoi ordinare le categorie alfabeticamente\? + Il File picker non è riuscito a restituire il file all\'app \ 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 4c78f8661..5731595bd 100644 --- a/i18n/src/main/res/values-ja/strings.xml +++ b/i18n/src/main/res/values-ja/strings.xml @@ -137,7 +137,6 @@ バックアップを復元 バックアップファイルからライブラリを復元する バックアップディレクトリ - 自動バックアップ バックアップ頻度 最大バックアップ数 バックアップが作成されました @@ -188,8 +187,6 @@ Cookiesを削除しました データベースをクリアしてもよろしいですか?ライブラリにない項目の読んだ章と読書進捗はすべて失われます エントリーを削除しました - 追跡情報を更新 - 同期サービスでステータス、評価と最後に読んだ章を更新 バグの修正などに役立ちます。個人情報を送信しません 不明なエラー カテゴリーを更新中 @@ -540,8 +537,6 @@ OFF ON カテゴリ別のソート設定 - ライブラリを更新時、トラッカーも更新する - トラッカーを自動でリロード 制限:%s このシリーズの全項目をキャンセル ローカル ソース @@ -558,7 +553,7 @@ ダウンロードを開始します ダイナミック 一部のスマホメーカーはバックグラウンドサービスを終了する追加のアプリ制限を施しています。修正する方法についてはこのWebサイトをご覧ください。 - バックアップアクティビティ + 背景活動 MIUI最適化が有効な場合はバックアップ・復元が正常に機能しない恐れがあります。 最低 低い diff --git a/i18n/src/main/res/values-jv/strings.xml b/i18n/src/main/res/values-jv/strings.xml index 34770500f..4dab8b4dc 100644 --- a/i18n/src/main/res/values-jv/strings.xml +++ b/i18n/src/main/res/values-jv/strings.xml @@ -277,8 +277,6 @@ Tampilake kanthi ringkes nalika maca dibukak Pamisahan kaca kaping pindho Nganyari otomatis watesan piranti - Nganyari jejak otomatis - Nganyari pelacak nalika nganyari perpustakaan Setelan saben kategori kanggo ngurutake lan tampilan Apa sampeyan pengin mbusak kategori \"%s\"\? Busak kategori diff --git a/i18n/src/main/res/values-ka-rGE/strings.xml b/i18n/src/main/res/values-ka-rGE/strings.xml index 11a537fe1..874be7bdd 100644 --- a/i18n/src/main/res/values-ka-rGE/strings.xml +++ b/i18n/src/main/res/values-ka-rGE/strings.xml @@ -191,7 +191,6 @@ რეზერვის აღდგენა ბიბლიოთეკის აღდგენა რეზერვიდან რეზერვის ლოკაცია - ავტომატურად რეზერვის შექმნა რეზერვის შექმნის სიხშირე მაქსიმალური რეზერვი რეზერვი შექმნილია @@ -220,7 +219,6 @@ დარწმუნებული ბრძანდებით\? წაკითხული თავები და ბიბლიოთეკაში არ არსებული ჩანაწერების პროგრესი დაიკარგება ჩანაწერები წაშლილია ბიბლიოთეკის მანგების ყდის ცვლილება - თვალყურის დევნების განახლება ელემენტის ოპტიმიზაცუა უკვე გამორთულია ვერ მოხერხდა მოწყობილობის პარამეტრების გახსნა ვებსაიტი @@ -394,7 +392,6 @@ \n \nამ სერტიფიკატის ნდობით თქვენ თქვენს თავზე იღებთ რისკებს და პასუხისმგებლობას. ცალმხრივი სინქრონიზაცია თვალყურის სადევნებელ სერვისებში თავების პროგრესის განსაახლებლად. მიადევნე თვალყური ინდივიდუალურ ჩანაწერებს მათი ჩანართებიდან. - ანახლებს სტატუსს, შეფასებას და ბოლო თავს წაკითხულს თვალყურის სადევნებელ სერვისებიდან გადაფარება ვერ მოხერხდა CloudFlare-ს შემოვლა ორივე diff --git a/i18n/src/main/res/values-kk/strings.xml b/i18n/src/main/res/values-kk/strings.xml index 5fc179707..e3f9cc37c 100644 --- a/i18n/src/main/res/values-kk/strings.xml +++ b/i18n/src/main/res/values-kk/strings.xml @@ -188,7 +188,6 @@ Автоматты жаңартулар Жалғастыру Қолданба тілі - Бақылау қызметерін автоматты түрде жаңарту Әрқашан сұраңыз Әдепкі санат Сұрыптау және көрсету үшін әр санат баптауы @@ -248,7 +247,6 @@ Жазбаларды жаңартуды өткізіп жіберу Бұл басталған жоқ Кітапхананы жаңарту кезінде жаңа мұқаба мен мәліметтерді тексеру - Кітапхананы жаңарту кезінде бақылау қызметтерін жаңарту Жаңартулар күтілуде Барлығын жаңарту Ескірген @@ -421,13 +419,11 @@ Күші жойылған Басылымы яқталды Кітапханаға қосу - Бақылау қызметтері үшін күйді, рейтингті және соңғы оқылған тарауды жаңартады Қателер тіркеулерімен бөлісу Сенімдісіз бе\? Кітапханадағы емес жазбалардың оқылған тараулары мен прогрессі жоғалады Жазбалар жойылды Тазалайтын түк жоқ Туындылар мұқабасын жаңарту - Бақылауды жаңарту Cloudflare айналып өтілмеді Жақсырақ үйлесімділік үшін WebView-ді жаңартыңыз Сақтық көшірме бумасы @@ -513,7 +509,6 @@ Ауқымды іздеу… \"%1$s\" ауқымды іздеу Іздеу - Автоматты сақтық көшірме User agent-ті әдепкіге қайтару Кеш тазаланды. %1$d файл жойылды Жаңартуларға тексеру diff --git a/i18n/src/main/res/values-kn/strings.xml b/i18n/src/main/res/values-kn/strings.xml index a554ee16b..9f73b9a18 100644 --- a/i18n/src/main/res/values-kn/strings.xml +++ b/i18n/src/main/res/values-kn/strings.xml @@ -125,7 +125,6 @@ ಬ್ಯಾಕಪ್ ರಚಿಸಲಾಗಿದೆ ಗರಿಷ್ಠ ಬ್ಯಾಕಪ್‌ಗಳು ಬ್ಯಾಕಪ್ ಆವರ್ತನ - ಸ್ವಯಂಚಾಲಿತ ಬ್ಯಾಕಪ್ ಬ್ಯಾಕಪ್ ಸ್ಥಳ ಬ್ಯಾಕಪ್ ಫೈಲ್‌ನಿಂದ ಗ್ರಂಥಾಲಯವನ್ನು ಮರುಸ್ಥಾಪಿಸಿ ಬ್ಯಾಕಪ್ ಮರುಸ್ಥಾಪಿಸಿ @@ -390,8 +389,6 @@ ಬ್ಯಾಟರಿ ಆಪ್ಟಿಮೈಸೇಶನ್ ಅನ್ನು ಈಗಾಗಲೇ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ ಹಿನ್ನೆಲೆ ಗ್ರಂಥಾಲಯದ ನವೀಕರಣಗಳು ಮತ್ತು ಬ್ಯಾಕಪ್‌ಗಳೊಂದಿಗೆ ಸಹಾಯ ಮಾಡುತ್ತದೆ ಬ್ಯಾಟರಿ ಆಪ್ಟಿಮೈಸೇಶನ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ - ಟ್ರ್ಯಾಕಿಂಗ್ ಸೇವೆಗಳಿಂದ ಓದಿದ ಸ್ಥಿತಿ, ಸ್ಕೋರ್ ಮತ್ತು ಕೊನೆಯ ಅಧ್ಯಾಯವನ್ನು ನವೀಕರಿಸಿ - ಟ್ರ್ಯಾಕಿಂಗ್ ಅನ್ನು ರಿಫ್ರೆಶ್ ಮಾಡಿ ಗ್ರಂಥಾಲಯದ ಮಾಂಗಾ ಕವರ್‌ಗಳನ್ನು ರಿಫ್ರೆಶ್ ಮಾಡಿ ನಮೂದುಗಳನ್ನು ಅಳಿಸಲಾಗಿದೆ ನೀವು ಖಚಿತವಾಗಿರುವಿರಾ\? ಅಧ್ಯಾಯಗಳು ಗ್ರಂಥಾಲಯೇತರ ಮಾಂಗಾದ ಓದು ಮತ್ತು ಪ್ರಗತಿ ಕಳೆದುಹೋಗುತ್ತದೆ @@ -555,8 +552,6 @@ ಆಫ ಆನ್ ಪ್ರತಿ ವರ್ಗದ ವಿಂಗಡಣೆ ಮತ್ತು ಪ್ರದರ್ಶನಕ್ಕಾಗಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳು - ಲೈಬ್ರರಿಯನ್ನು ನವೀಕರಿಸುವಾಗ ಟ್ರ್ಯಾಕರ್‌ಗಳನ್ನು ನವೀಕರಿಸಿ - ಟ್ರ್ಯಾಕರ್‌ಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ರಿಫ್ರೆಶ್ ಮಾಡಿ ನಿರ್ಬಂಧಗಳು: %s ಈಗಲೇ ಡೌನ್‌ಲೋಡ್ ಪ್ರಾರಂಭಿಸಿ \ No newline at end of file diff --git a/i18n/src/main/res/values-ko/strings.xml b/i18n/src/main/res/values-ko/strings.xml index fa2cd8cae..7144abc7d 100644 --- a/i18n/src/main/res/values-ko/strings.xml +++ b/i18n/src/main/res/values-ko/strings.xml @@ -133,12 +133,11 @@ 끄기 마지막 회차 새로운 화 다운로드 - 서비스 + 트래킹 서비스 백업 생성 백업 복원 백업 파일에서 서재 복원 백업 위치 - 자동 백업 백업 주기 최대 백업 백업 생성됨 @@ -154,8 +153,6 @@ 데이터베이스 삭제 서재에 추가되지 않은 항목의 기록을 삭제합니다 확실합니까\? 서재에 없는 항목의 읽은 기록이 삭제됩니다 - 트래커 동기화 새로고침 - 상태 및 평점, 마지막으로 읽은 회차를 동기화 서비스로부터 업데이트합니다 버전 오류 보고서 전송 버그를 수정하는데 도움이 됩니다. 개인 정보는 전송되지 않습니다 @@ -383,7 +380,6 @@ 번역에 참여하기 회전 설정 메타데이터 자동 갱신 - 트래커 자동 갱신 현재 만화에만 적용 읽기 모드 서재의 모든 항목에 적용됩니다 @@ -567,18 +563,17 @@ 옥색 딸기 칵테일 확장 앱 목록 가져오기 실패 - 서재 업데이트 시 트래커 갱신 제외: %s 이 확장앱은 공식 확장앱이 아닙니다. - 트래커 서비스에 항목 진행 상황을 동기화합니다. 트래킹 버튼을 이용하여 각각의 항목 별로 트래킹을 설정하세요. + 트래킹 서비스에 항목 진행 상황을 업데이트합니다. 트래킹 버튼을 이용하여 각각의 항목 별로 트래킹을 설정하세요. 트래커 가이드 - 향상된 서비스 + 향상된 트래킹 서비스 카테고리가 다운로드에서 제외된 경우 다른 카테고리에 포함되어 있어도 다운로드 되지 않습니다. - 특정 소스에 향상된 서비스를 제공합니다. 서재에 항목이 추가될 시 자동으로 트래킹 됩니다. + 특정 소스에 대해 향상된 기능을 제공합니다. 서재에 항목이 추가될 시 자동으로 트래킹 됩니다. 백업 파일에서 데이터가 복구됩니다. \n \n복구 완료 후 없어진 소스를 다시 설치하고 트래킹 서비스에 로그인 해야 합니다. - 백업 파일은 복사하여 다른 장소에 나눠 보관하세요. + 백업 파일은 복사하여 다른 장소에 나눠 보관하세요. 백업 파일에는 비밀번호 등의 민감한 정보가 포함될 수 있습니다. 백업 파일 공유시 주의하세요. 백그라운드 서재 업데이트와 라이브러리 업데이트를 도울 수 있습니다 자세한 로그 자세한 로그를 시스템 로그에 기록 (성능이 하락할 수 있습니다) @@ -795,7 +790,12 @@ 인터넷에 연결되지 않음 포기했나요\? 20일 ~ 2달 이내 항상 평가하기 - 트랙킹 서비스 로그인 + 트래킹 서비스 로그인 HTTP %d, WebView의 웹 사이트를 확인해 주세요 %s에 연결할 수 없습니다 + 카테고리 정렬 + 서재 업데이트 중...(%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 6b24a071c..19b51d0f2 100644 --- a/i18n/src/main/res/values-lt/strings.xml +++ b/i18n/src/main/res/values-lt/strings.xml @@ -28,8 +28,6 @@ Vardas Visada klausti Numatyta kategorija - Naujinti seklius kai biblioteka naujinama - Automatiškai naujinti seklius Tikrinti naujus viršelius ir informaciją kai biblioteka naujinama Automatiškai naujinti metaduomenis Kai yra \"Perskaityta\" statusas @@ -335,7 +333,6 @@ Leisti naikinti žymėtus skyrius Penktas nuo paskutinio skaityto Automatinis atsisiuntimas - Automatinės atsarginės kopijos Maksimalus atsarginių kopijų skaičius Sukurta atsarginė kopija aukštas @@ -511,7 +508,6 @@ Atkūrimas jau vyksta Atkuriama atsarginė kopija Kad įsigaliotų, reikia iš naujo paleisti programą - Atnaujina būseną, įvertinimą ir paskutinį perskaitytą skyrių iš sekimo paslaugų Iš naujo nustatyti kiekvienos serijos skaitytuvo nustatymus Išmeskite strigčių žurnalus Nepavyko atsisiųsti skyrių. Galite pabandyti dar kartą atsisiųsti @@ -558,7 +554,6 @@ Iš naujo nustatyti numatytąją vartotojo agento eilutę Išvalyti \"WebView\" duomenis Atnaujinti bibliotekos viršelius - Atnaujinti stebėjimą Iš naujo nustatyti visų serijų skaitymo režimą ir orientaciją Visų skaitytuvo nustatymų nustatymas iš naujo Nepavyko atstatyti skaitytuvo nustatymų diff --git a/i18n/src/main/res/values-lv/strings.xml b/i18n/src/main/res/values-lv/strings.xml index f498f0e1a..ac63f614d 100644 --- a/i18n/src/main/res/values-lv/strings.xml +++ b/i18n/src/main/res/values-lv/strings.xml @@ -189,7 +189,6 @@ 18+ Autentificējaties, lai apstriprinātu izmaiņas Ar \'\'Pabeigts\'\' statusu - Automātiski atsvaidzina izsekotājus Sākt lejupielādi tūlīt Neizdevās iegūt paplašinājumu sarakstu Īsi parādīt, kad ir atvērts lasītājs @@ -236,7 +235,6 @@ Automātiskie atjauninājumi Katru nedēļu Automātiskās atjaunināšanas ierīču ierobežojumi - Atjaunināt izsekotājus, atjauninot bibliotēku Izslēgt: %s Novecojis Instalēt @@ -394,7 +392,6 @@ Izveidot dublējumu Dublējuma atrašanās vieta Nederīgs dublējuma fails - Automātiskā dublēšana Dublējumu biežums Kopijas vajadzētu glabāt arī citās vietās. Dažiem ražotājiem ir papildu lietojumprogrammu ierobežojumi, kas iznīcina fona pakalpojumus. Šajā vietnē ir vairāk informācijas par to, kā to izlabot. @@ -428,7 +425,6 @@ Tīrīšanas laikā radās kļūda Notīrīt datu bāzi Dzēst vēsturi ierakstiem, kas nav saglabāti jūsu bibliotēkā - Atjaunina statusu, vērtējumu un pēdējo izlasīto nodaļu no izsekošanas servisa Atiestatīt atsevišķu sēriju lasītāja iestatījumus Atiestatīt katras sērijas lasīšanas režīmu un orientāciju Planšetdatora lietotāja interfeiss @@ -445,7 +441,6 @@ Nevarēja atvērt ierīces iestatījumus Serviss Dublējums izveidots - Atsvaidzināt izsekošanu Visi lasītāja iestatījumi atiestatīti Nevarēja atiestatīt lasītāja iestatījumus Lai stātos spēkā, ir nepieciešama lietotnes restartēšana diff --git a/i18n/src/main/res/values-ms/strings.xml b/i18n/src/main/res/values-ms/strings.xml index 9dee603f6..8fd5b4e82 100644 --- a/i18n/src/main/res/values-ms/strings.xml +++ b/i18n/src/main/res/values-ms/strings.xml @@ -138,7 +138,6 @@ Pulihkan sandaran Pulihkan pustaka daripada fail sandaran Lokasi sandaran - Sandaran automatik Kekerapan sandaran Sandaran maksimum Sandaran dicipta @@ -156,8 +155,6 @@ Hapus sejarah entri yang tidak disimpan di dalam pustaka Adakah anda pasti\? Bab dibaca dan kemajuan entri bukan-pustaka akan hilang Entri dihapuskan - Segar semula penjejakan - Kemas kini status, skor dan bab terakhir dibaca dari perkhidmatan penjejakan Versi Hantar laporan ranap Bantu membaiki aplikasi. Tiada data sensitif dihantar @@ -534,8 +531,6 @@ Susun mengikut Format bab tidak sah Bab tidak dijumpai - Kemas kini penjejak ketika mengemaskini pustaka - Segar semula penjejak secara automatik Sekatan: %s Sumber setempat Mati diff --git a/i18n/src/main/res/values-nb-rNO/strings.xml b/i18n/src/main/res/values-nb-rNO/strings.xml index 11dfd4eba..dd3899d55 100644 --- a/i18n/src/main/res/values-nb-rNO/strings.xml +++ b/i18n/src/main/res/values-nb-rNO/strings.xml @@ -157,7 +157,6 @@ Gjenopprett sikkerhetskopi Gjenopprett bibliotek fra sikkerhetskopifil Sikkerhetskopi-mappe - Automatisk sikkerhetskopi Sikkerhetskopieringsfrekvens Maks antall sikkerhetskopier Sikkerhetskopi opprettet @@ -175,8 +174,6 @@ Slett historikk for oppføringer som ikke er lagret i biblioteket ditt Er du sikker\? Leste kapitler og framdrift for oppføringer som ikke er i biblioteket vil gå tapt Oppføringer slettet - Oppdater sporing - Oppdaterer status, poengsum og sist leste kapittel fra sporingstjenestene Versjon Send krasjrapporter Hjelper til med fiksing av feil. Ingen sensitiv data vil bli sendt @@ -534,7 +531,6 @@ Stående Rotasjon Handlinger - Oppdater trackere automatisk Helt svart Oppstartsveiledning Du har ingen kategorier enda. @@ -591,7 +587,6 @@ Ingen treff funnet Skru av inkognito-modus Bistå oversettelsen - Oppdater trackere ved oppdatering av bibliotek Yotsuba Installer og start Shizuku for å bruke det som utvidelsesinstallatør. Shizuku kjører ikke diff --git a/i18n/src/main/res/values-ne/strings.xml b/i18n/src/main/res/values-ne/strings.xml index 9b8f3aa51..5d594acf9 100644 --- a/i18n/src/main/res/values-ne/strings.xml +++ b/i18n/src/main/res/values-ne/strings.xml @@ -113,8 +113,6 @@ राखिएको मिती अध्याय ल्याएको मिति सबैभन्दा नयाँ अध्याय - पुस्तकालय अपडेट गर्दा ट्र्याकरहरू अपडेट गर्नुहोस् - ट्र्याकरहरू स्वचालित रूपमा रिफ्रेस गर्नुहोस् पुस्तकालय अपडेट गर्दा नयाँ आवरण र विवरणहरूको लागि जाँच गर्नुहोस् मेटाडेटा स्वतः रिफ्रेस गर्नुहोस् \"समाप्त\" स्थिति भएको @@ -421,7 +419,6 @@ दायाँ ब्याकअप रिस्टोर गर्नुहोस् ब्याकअप फाइलबाट पुस्तकालय रिस्टोर गर्नुहोस् - स्वचालित ब्याकअपहरू ब्याकअपमा कुनै पनि पुस्तकालयका इन्ट्री समावेश छैन। ब्याकअप स्थान ब्याकअप फ्रिक्वेन्सी @@ -493,8 +490,6 @@ पुस्तकालयमा नभएका इन्ट्रीको इतिहास हटाउनुहोस् के तपाईँ निश्चित हुनुहुन्छ\? तपाईंले पढ्नुभएको अध्यायहरू र गैर-पुस्तकालय इन्ट्रीहरूको प्रगति हराउनेछ सफा गर्न केही छैन - ट्र्याकिङ रिफ्रेस गर्नुहोस् - ट्र्याकिङ सेवाहरूबाट स्थिति, स्कोर र अन्तिम पढिएको अध्याय अपडेट गर्दछ संस्करण वेबसाइट अनुवाद गर्न मद्दत गर्नुहोस् diff --git a/i18n/src/main/res/values-nl/strings.xml b/i18n/src/main/res/values-nl/strings.xml index a36e8e3b8..8a7bfce97 100644 --- a/i18n/src/main/res/values-nl/strings.xml +++ b/i18n/src/main/res/values-nl/strings.xml @@ -113,7 +113,6 @@ Back-up herstellen Herstellen van back-up bestand Back-uplocatie - Automatische backups Back-upfrequentie Maximaal aantal back-ups Back-up gemaakt @@ -124,7 +123,6 @@ Gebruikt: %1$s Verwijder cookies Cookies verwijdered - Update status, score en laatst gelezen hoofdstuk van de trackingdiensten Versie Log in op %1$s Gebruikersnaam @@ -204,7 +202,6 @@ Fout opgetreden tijdens het wissen Database leegmaken Verwijder geschiedenis voor items die niet in je bibliotheek zijn opgeslagen - Tracking bijwerken Rapporteer bugs Helpt bij het oplossen van bugs. Er wordt geen gevoelige data verzonden Niks recent gelezen @@ -554,8 +551,6 @@ Uit Aan Instellingen per categorie voor sorteren en weergeven - Trackers bijwerken bij het bijwerken van de bibliotheek - Trackers automatisch vernieuwen Lokale bron Er zijn nog geen categorieën. Begin nu met downloaden diff --git a/i18n/src/main/res/values-nn/strings.xml b/i18n/src/main/res/values-nn/strings.xml index ece30340f..2d60827fd 100644 --- a/i18n/src/main/res/values-nn/strings.xml +++ b/i18n/src/main/res/values-nn/strings.xml @@ -259,7 +259,6 @@ Kan innehalda NSFW (18+) innhald Slett kapittel Manga i utelatne kategoriar vil ikkje bli nedlasta sjølv om dei òg er i inkluderte kategoriar. - Automatisk reservekopiar Reservekopifrekvens Avbroten gjenoppretting Manglande kjelder: diff --git a/i18n/src/main/res/values-pl/strings.xml b/i18n/src/main/res/values-pl/strings.xml index 42ddf429d..1e2c3ab5e 100644 --- a/i18n/src/main/res/values-pl/strings.xml +++ b/i18n/src/main/res/values-pl/strings.xml @@ -181,7 +181,6 @@ Lokalizacja kopii zapasowych Częstotliwość tworzenia kopii Maks. ilość kopii automatycznych - Automatyczna kopia zapasowa Co zawrzeć w kopii zapasowej? Przywracanie kopii zapasowej Tworzenie kopii zapasowej @@ -199,8 +198,6 @@ Przywracanie ukończone Na pewno\? Przeczytane rozdziały i postęp w wpisach spoza biblioteki zostaną utracone Pozycje usunięte - Odśwież dane śledzenia - Aktualizuje status, ocenę i ostatnio czytany rozdział na podstawie usług śledzenia Zalogowano Źródło lokalne Nieukończone @@ -567,8 +564,6 @@ Sortowanie Błędny format rozdziału Nie znaleziono rozdziału - Automatycznie odświeżaj serwisy śledzące - Aktualizuj serwisy śledzące podczas aktualizacji biblioteki Błąd przy udostępnianiu okładki Błąd przy zapisie okładki Okładka zapisana diff --git a/i18n/src/main/res/values-pt-rBR/strings.xml b/i18n/src/main/res/values-pt-rBR/strings.xml index bcebc749c..c3a1ae552 100644 --- a/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/i18n/src/main/res/values-pt-rBR/strings.xml @@ -137,9 +137,8 @@ Restaurar backup Restaura a biblioteca de um arquivo de backup Local de backup - Backups automáticos - Frequência de backup - Máximo de backups + Frequência de backup automático + Máximo de backups automáticos Backup criado Restauração concluída Do que você deseja fazer backup\? @@ -155,8 +154,6 @@ Exclui o histórico de itens que não estão salvos em sua biblioteca Tem certeza\? Os capítulos lidos e o progresso em itens que não estão na sua biblioteca serão perdidos Entradas excluídas - Atualizar o monitoramento - Atualiza os estados, as avaliações e os últimos capítulos lidos dos serviços de monitoramento Versão Enviar relatórios de erro Ajuda a corrigir eventuais erros. Nenhum dado sensível será enviado @@ -556,8 +553,6 @@ Ordenar por Formato de capítulo inválido Capítulo não encontrado - Atualizar os monitoradores durante a atualização da biblioteca - Atualizar os monitoradores automaticamente Restrições: %s Fonte local Desligado @@ -719,7 +714,7 @@ Download automático, download a frente Sincronização de progresso unidirecional, sincronização aprimorada Fontes, extensões, pesquisa global - Backups manuais e automáticos + Backups manuais e automáticos, espaço de armazenamento Bloqueio do aplicativo, tela segura Exportar registros de travamento, otimizações de bateria Ooops! @@ -838,4 +833,5 @@ Ordenar as categorias Você deseja ordenar as categorias alfabeticamente\? O seletor de arquivos não retornou o arquivo para o aplicativo + Dados e armazenamento \ 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 34e173676..c6ba00a29 100644 --- a/i18n/src/main/res/values-pt/strings.xml +++ b/i18n/src/main/res/values-pt/strings.xml @@ -246,7 +246,6 @@ Pode ser usado para restaurar a biblioteca atual Restaurar cópia de segurança Restaurar biblioteca a partir de cópia de segurança - Cópias de segurança automáticas Frequência de cópia de segurança Restaurando cópia de segurança Criando cópia de segurança @@ -269,8 +268,6 @@ Abrir em WebView Cores 32-bit Ignorar capítulos marcados como lido - Atualizar monitorização - Atualiza estado, avaliações e últimos capítulos lidos dos serviços de monitorização Sem mais resultados Fonte local Outras @@ -610,8 +607,6 @@ Fonte não é suportada Serviços que oferecem recursos aprimorados para fontes específicas. Os itens são automaticamente monitorados quando adicionados na sua biblioteca. Serviços melhorados - Atualizar monitorizadores automaticamente - Atualizar monitorizadores ao atualizar biblioteca Guia de introdução Azul-petróleo e Turquesa diff --git a/i18n/src/main/res/values-ro/strings.xml b/i18n/src/main/res/values-ro/strings.xml index 778ecfa21..d44b6cd06 100644 --- a/i18n/src/main/res/values-ro/strings.xml +++ b/i18n/src/main/res/values-ro/strings.xml @@ -162,7 +162,6 @@ Restaurează copia de rezervă Restaurează biblioteca din fișierul copiei de rezervă Locația copiei de rezervă - Copii de rezervă create automat Frecventă de creere a copiilor de rezervă Numărul maxim de copii de rezervă Backup creat @@ -180,8 +179,6 @@ Ștergeți istoricul pentru intrările care nu sunt salvate în bibliotecă Ești sigur\? Capitolele citite și progresul intrărilor din afara bibliotecii vor fi pierdute Înregistrări șterse - Reîncărca urmărirea - Actualizează starea, scorul și ultimul capitol citit de la serviciile de urmărire Versiune Trimite rapoarte pt. eșuări Ajută la rezolvarea bug-urilor. Informațiile sensibile nu vor fi trimise @@ -613,7 +610,6 @@ Shizuku nu rulează Limba aplicației Restricții: %s - Reîmprospătați automat trackerele Cel mai înalt Înalt Scăzut @@ -626,7 +622,6 @@ Este posibil să nu funcționeze corect backup/restaurare dacă MIUI Optimization este dezactivată. La fiecare 3 zile Doar prin Wi Fi - Actualizeaza trackerele la actualizarea bibliotecii Formatul RARv5 nu este acceptat Oprit Informații despre aplicație @@ -770,4 +765,6 @@ %1$s eroare: %2$s *necesar Copiat in clipboard + Deblochează %s + Șterge descărcările \ 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 1141809a9..ea72d69cd 100644 --- a/i18n/src/main/res/values-ru/strings.xml +++ b/i18n/src/main/res/values-ru/strings.xml @@ -211,13 +211,10 @@ Больше нет результатов Папка резервной копии Частота резервных копий - Автоматические резервные копии Количество резервных копий Создать резервную копию Можно использовать для восстановления текущей библиотеки Обрезать поля - Обновить отслеживание - Обновляет статус, оценку и последнюю прочитанную главу для сервисов отслеживания Восстановить из резервной копии Восстановить библиотеку из резервной копии Восстановление завершено @@ -296,7 +293,7 @@ Вперед Обновить Библиотека - Устарело + Устаревшее Это расширение больше недоступно. Оно может работать неправильно, а также вызвать проблемы с приложением. Рекомендуется его удалить. Формат даты Глобальное обновление @@ -567,8 +564,6 @@ Сортировать по Недопустимый формат глав Глава не найдена - Обновлять отслеживание при обновлении библиотеки - Обновлять отслеживание Ограничения: %s Источник пользователя Выключено diff --git a/i18n/src/main/res/values-sa/strings.xml b/i18n/src/main/res/values-sa/strings.xml index 56b9683a8..04a955d27 100644 --- a/i18n/src/main/res/values-sa/strings.xml +++ b/i18n/src/main/res/values-sa/strings.xml @@ -200,9 +200,7 @@ %d वर्गः %d वर्गौ - ग्रन्थालयनवीकरणे सति ट्राकर्तन्त्रांशान् नवीकरोतु प्रदत्तांशं स्वयञ्चालितं नवीकरोतु - ट्राकर्तन्त्रांशान् स्वयञ्चालितं नवीकरोतु प्रतिवर्गं विन्यासस्य प्रदर्शनस्य च कृते समायोजनानि अविश्वस्तविस्तारः अयं विस्तारः टाचीयोमेः अधिकारिकविस्तारसूच्याः नास्ति। @@ -339,7 +337,6 @@ एतत् उपयुज्य वर्तमानग्रन्थालयं समादातुं शक्यते प्रतिलेखनं समाददातु प्रतिलेखनस्थलम् - स्वयङ्कृतप्रतिलेखनम् प्रतिलेखनस्य आवर्तनता अधिकतमप्रतिलेखनानि प्रतिलेखनं पूर्वमेव प्रगतौ अस्ति @@ -454,7 +451,6 @@ अवारोपणसाधनम् सामान्यम् - अनुप्रज्ञानं नवीकरोतु प्रच्छन्ननामदशा ज्ञापकानि मार्जयतु ज्ञापकानि मार्जितानि @@ -602,7 +598,6 @@ १ अध्यायं लङ्घयति यतः मूले सः अनुपस्थितः अस्ति उत सः बहिः सम्मृष्टः कृतः २ अध्यायौ लङ्घयति यतः मूले तौ अनुपस्थितौ स्तः उत तौ बहिः सम्मृष्टौ कृतौ - अनुप्रज्ञानसेवाभ्यः स्थितिं प्राप्ताङ्कं अन्तिमपठिताध्यायं च नवीकरोति व्युत्पादकेभ्यः प्रसारयितुं दोषदत्तम् एकस्यां सञ्चिकायां रक्षति इमानि समायोजनानि प्राथमिकानि इव रक्षितुं त्वं निश्चितं किम् स्खलितानां परिहरणे साहाय्यं करिष्यति। संवेदनशीलदत्तांशाः न प्रेषिष्यते॥ diff --git a/i18n/src/main/res/values-sah/strings.xml b/i18n/src/main/res/values-sah/strings.xml index 486d9d40e..99b601462 100644 --- a/i18n/src/main/res/values-sah/strings.xml +++ b/i18n/src/main/res/values-sah/strings.xml @@ -248,7 +248,6 @@ Хаппаас куопуйа оҥоһуллунна Муҥутугар дылы хаппаас куопуйалар Хаппаас куопуйа оҥоһуутун түргэнэ - Автоматическай Хаппаас куопуйалар Хаппаас куопуйа сурунаала Бэбэлэтиэкэни хаппаас куопуйа билэтиттэн төнүҥнэрии Хаппаас куопуйаны куолутунан туруоруу @@ -279,8 +278,6 @@ Эн бэбэлэтиэкэҕэр суох маанга остуоруйатын сотторуу Билим олоҕо ыраастааһына Батарея тупсарыытын араарыы - Туругу, ахсааны уонна бүтэһик ааҕыллыбыт түһүмэҕи кэтээн көрөр өҥөлөртөн саҥардыы - Кэтээһини чэбдигирии Бэбэлэтиэкэҕэ баар маанга таһын чэбдигирии Дааннайдар сотуллубуттар Бэбэлэтиэкэ уонна хаппаас куопуйатыгар кэннинээҕи саҥардыытыгар көмөлөһөр diff --git a/i18n/src/main/res/values-sc/strings.xml b/i18n/src/main/res/values-sc/strings.xml index 3ad59ed0d..bcfe5ef2c 100644 --- a/i18n/src/main/res/values-sc/strings.xml +++ b/i18n/src/main/res/values-sc/strings.xml @@ -163,7 +163,6 @@ Riprìstina una còpia de seguresa Riprìstina sa biblioteca dae una còpia de seguresa Cartella de sa còpia de seguresa - Còpias de seguresa automàticas Frecuèntzia de sarvatàgiu de sas còpias de seguresa Màssimu de còpias de seguresa Còpia de seguresa creada @@ -181,8 +180,6 @@ Iscantzella sa cronologia pro sos elementos chi non sunt sarvados in sa biblioteca tua Seguru ses\? Sos capìtulos lèghidos e su progressu de sos elementos chi non sunt in sa biblioteca s\'ant a pèrdere Boghes iscantzelladas - Annoa s\'arrastamentu - Agiornat s\'istadu, su votu e s\'ùrtimu capìtulu lèghidu dae sos servìtzios de arrastamentu Versione Imbia raportos a pitzu de sos arrestos anòmalos Agiudat a acontzare cale si siat faddina. Perunu datu sensìbile at a èssere imbiadu @@ -545,8 +542,6 @@ Òrdina pro Formadu de su capìtulu non vàlidu Capìtulu no agatadu - Agiorna sos arrastadores cando agiornas sa biblioteca - Annoa sos arrastadores automaticamente Istudadu Allutu Restritziones: %s diff --git a/i18n/src/main/res/values-sk/strings.xml b/i18n/src/main/res/values-sk/strings.xml index 7422c9dce..6eb94a300 100644 --- a/i18n/src/main/res/values-sk/strings.xml +++ b/i18n/src/main/res/values-sk/strings.xml @@ -173,7 +173,6 @@ Obnoviť zálohu Obnoviť knižnicu zo záložného súboru Adresár na zálohy - Automatické zálohovanie Frekvencia zálohovania Maximálny počet záloh Záloha bola vytvorená @@ -197,8 +196,6 @@ Zastaraný Toto rozšírenie už nie je k dispozícii. Záznamy boli odstránené - Obnoviť sledovanie - Aktualizuje stav, skóre a poslednú čítanú kapitolu zo sledovacích služieb Verzia Odosielať správy o zlyhaní Pomáha opraviť akékoľvek chyby. Nebudú odoslané žiadne citlivé údaje @@ -409,8 +406,6 @@ Globálna aktualizácia Automatický obnoviť metadata Pri aktualizácii knižnice skontrolujte nový obal a podrobnosti - Automaticky obnovovať sledovače - Aktualizujte sledovače pri aktualizácii knižnice Zobraziť Každé 3 dni Aktualizácia už prebieha diff --git a/i18n/src/main/res/values-sq/strings.xml b/i18n/src/main/res/values-sq/strings.xml index 24288457c..0b7da30c8 100644 --- a/i18n/src/main/res/values-sq/strings.xml +++ b/i18n/src/main/res/values-sq/strings.xml @@ -190,9 +190,7 @@ Me statusin \"Përfunduar\" Kjo nuk ka filluar Çdo 2 ditë - Rifresko automatikisht gjurmuesit Rifresko automatikisht të dhënat meta - Përditësoni gjurmuesit kur përditësoni bibliotekën Gjithmonë pyesni Instaloni Cilësimet sipas kategorisë për renditjen dhe shfaqjen @@ -416,7 +414,6 @@ Kindle-ish Shërbime që ofrojnë veçori të përmirësuara për burime specifike. Regjistrimet gjurmohen automatikisht kur shtohen në bibliotekën tuaj. Pista - Rezervime automatike Frekuenca rezervë Rezervimet maksimale Gjurmuesit nuk kanë hyrë në: @@ -559,8 +556,6 @@ %1$d hyrje jashtë bibliotekës në bazën e të dhënave Pastro të dhënat e WebView Rifresko kopertinat e bibliotekës - Rifresko gjurmimin - Përditëson statusin, rezultatin dhe kapitullin e fundit të lexuar nga shërbimet e gjurmimit Rivendos cilësimet e lexuesit për seri Rivendos modalitetin e leximit dhe orientimin e të gjitha serive Cilësimet e lexuesit nuk mund të rivendoseshin diff --git a/i18n/src/main/res/values-sr/strings.xml b/i18n/src/main/res/values-sr/strings.xml index 437700083..1772e56a0 100644 --- a/i18n/src/main/res/values-sr/strings.xml +++ b/i18n/src/main/res/values-sr/strings.xml @@ -162,7 +162,6 @@ Врати се на резервну копију Врати се на колекцију из резервне копије Локација резервних копија - Аутоматско прављење резервних копија Учесталост прављења резервних копија Максималан број резервних копија Направљена је резервна копија @@ -180,8 +179,6 @@ Обриши историју за наслове који нису сачувани у твојој колекцији Да ли сте сигурни\? Изгубићете прочитана поглавља и статус наслова који нису у колекцији Уноси избрисани - Освежи праћење - Ажурирај статус, оцену и последње прочитано поглавље из трекера Верзија Пошаљи извештаје грешака Помози у поправљању кварова. Ниједан осетљив податак неће бити послат @@ -553,8 +550,6 @@ Раздели широке странице Ништа Смањује оштре прелазе међу нијансама, али утиче на перформансе - Аутоматски освежи пратиоце - Ажурирај пратиоце при ажурирању колекције Датум Начин навигације Непознат аутор diff --git a/i18n/src/main/res/values-sv/strings.xml b/i18n/src/main/res/values-sv/strings.xml index 6790072de..aad384aeb 100644 --- a/i18n/src/main/res/values-sv/strings.xml +++ b/i18n/src/main/res/values-sv/strings.xml @@ -162,7 +162,6 @@ Återställ säkerhetskopia Återställ biblioteket från en säkerhetskopia Säkerhetskopieringsplats - Automatiska säkerhetskopior Säkerhetskopieringsfrekvens Maximala säkerhetskopior Säkerhetskopia skapad @@ -180,8 +179,6 @@ Ta bort historik för inlägg som inte finns i ditt bibliotek Är du säker på det\? Lästa kapitel och framsteg för poster som inte finns i biblioteket kommer att gå förlorade Inlägg raderade - Uppdatera spårning - Uppdaterar status, betyg och senaste kapitel läst från spårningstjänsterna Version Skicka kraschrapporter Hjälper till att fixa eventuella buggar. Inga känsliga uppgifter skickas @@ -545,8 +542,6 @@ Sortera efter Ogiltigt kapitelformat Kapitlet hittades inte - Uppdatera spårare när du uppdaterar biblioteket - Uppdatera spårare automatiskt Begränsningar: %s Lokal källa Av diff --git a/i18n/src/main/res/values-th/strings.xml b/i18n/src/main/res/values-th/strings.xml index 26e3397ee..ee25ac2d8 100644 --- a/i18n/src/main/res/values-th/strings.xml +++ b/i18n/src/main/res/values-th/strings.xml @@ -163,7 +163,6 @@ เรียกคืนค่าการสำรองข้อมูล เรียกคืนค่าคลังจากแฟ้มข้อมูลสำรอง ตําแหน่งที่ตั้งข้อมูลสํารอง - สํารองข้อมูลอัตโนมัติ ความถี่ในการสำรองข้อมูล จำนวนการสำรองข้อมูลสูงสุด สร้างการสำรองข้อมูลแล้ว @@ -181,8 +180,6 @@ ลบประวัติรายการที่ไม่ได้บันทึกไว้ในคลัง แน่ใจไหม\? ข้อมูลการอ่านของรายการที่ไม่ได้อยู่ในคลังจะหายไป ลบรายการแล้ว - โหลดข้อมูลการติดตามใหม่ - อัปเดตสถานะคะแนนและตอนสุดท้ายที่อ่านจากบริการติดตาม เวอร์ชัน ส่งรายงานความผิดพลาด ช่วยแก้ไขจุดบกพร่องต่างๆ จะไม่มีการส่งข้อมูลที่สำคัญ @@ -558,8 +555,6 @@ แอพอัปเดต ค่าเริ่มต้น ผิดพลาดในการแบ่งปันปก - โหลดตัวติดตามใหม่โดยอัตโนมัติ - อัปเดตตัวติดตามเมื่ออัปเดตคลัง เริ่มดาวน์โหลดเลย %1$d วันที่ผ่านมา @@ -805,4 +800,5 @@ ต้องการจัดเรียงหมวดหมู่ตามตัวอักษรหรือไม่\? การตั้งค่าแหล่งที่มา การตั้งค่าแอป + เครื่องมือเลือกไฟล์ไม่สามารถส่งต่อไฟล์ไปยังแอปได้ \ 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 422f490d9..5980655f8 100644 --- a/i18n/src/main/res/values-tr/strings.xml +++ b/i18n/src/main/res/values-tr/strings.xml @@ -156,13 +156,12 @@ Okunan sondan dördüncü bölüm Okunan sondan beşinci bölüm Yeni bölümleri indir - Hizmetler + İzleyiciler Yedek oluştur Şu anki kitaplığı geri yüklemek için kullanılabilir Yedeği geri yükle Kitaplığı yedek dosyasından geri yükle Yedekleme konumu - Kendiliğinden yedekleme Yedekleme sıklığı Maksimum yedek Yedek oluşturuldu @@ -180,8 +179,6 @@ Kitaplığına kaydedilmeyen girdilerin geçmiş bilgisini sil Emin misin\? Kitaplıkta olmayan girdilerin okunan bölümleri ve ilerlemesi kaybolacak Girdiler silindi - İzlemeyi yenile - İzleme hizmetlerinden durumu, puanı ve son okunan bölümü günceller Sürüm Çökme bildirimi gönder Hataların düzeltilmesine yardımcı olur. Hiçbir duyarlı veri gönderilmez @@ -409,7 +406,7 @@ %1$s içinde %2$s hatayla tamamlandı %1$s içinde %2$s hatayla tamamlandı - Bölüm ilerlemesini, izleme hizmetlerinde güncellemek için tek yönlü eşitleme. Her girdinin izleme düğmesinden, izlemeyi ayarlayın. + Bölüm ilerlemesini, harici 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 dizelgeden değil. Resmi olmayan @@ -545,8 +542,6 @@ Sıralama ölçütü Geçersiz bölüm biçimi Bölüm bulunamadı - Kitaplığı güncellerken izleyicileri güncelle - İzleyicileri kendiliğinden yenile Kısıtlamalar: %s Yerel kaynak Açık @@ -561,8 +556,8 @@ Şimdi indirmeye başla Bazı üreticilerin arka plan hizmetlerini durduran ek uygulama kısıtlamaları vardır. Bu web sitesinde durumun nasıl düzeltileceği hakkında daha fazla bilgi var. Yedekleme/geri yükleme, MIUI iyileştirmesi devre dışıysa düzgün çalışmayabilir. - Belirli kaynaklar için gelişmiş özellikler sağlayan hizmetler. Girdiler, kitaplığınıza eklendiğinde kendiliğinden izlenir. - Gelişmiş hizmetler + Belirli kaynaklar için gelişmiş özellikler sağlar. Girdiler, kitaplığınıza eklendiğinde kendiliğinden izlenir. + Gelişmiş izleyiciler Arı kara karanlık kip Yotsuba Yin & Yang @@ -602,7 +597,7 @@ Toplam girdi Uyarı Dil - Yedeklerin kopyalarını başka yerlerde de tutmalısınız. + Yedeklerin kopyalarını başka yerlerde de tutmalısınız. Yedekler, depolanan şifreler dahil olmak üzere hassas verileri içerebilirler; paylaşırken dikkat edin. Büyük güncellemeler kaynaklara dokunca verir ve daha yavaş güncellemelere ve ayrıca pil kullanımının artmasına neden olabilir. Daha fazlasını öğrenmek için dokunun. Ayrıntılı günlük kaydı Ayrıntılı günlükleri sistem günlüğüne yaz (uygulama performansını düşürür) @@ -807,11 +802,19 @@ İndirilenler dizini geçersiz kılındı Cloudflare\'le ilgili yardım için tıklayın %s verisine erişilemedi - İzleme girişi + İzleyici 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 Diziyi en alta taşı + Ulamları sırala + Kitaplık güncelleniyor… (%s) + Ulamları alfabetik sıralamak ister misiniz\? + Dosya seçici dosyayı uygulamaya getirmekte başarısız oldu + Kaynak ayarları + Uygulama ayarları + Göreli zaman damgaları + \"%1$s\" yerine \"%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 da72e4a33..bdef440a1 100644 --- a/i18n/src/main/res/values-uk/strings.xml +++ b/i18n/src/main/res/values-uk/strings.xml @@ -162,7 +162,6 @@ Відновити резервну копію Відновити бібліотеку з резервної копії Директорія резервної копії - Автоматичне резервування Частота створення резервної копії Максимальна кількість резервних копій Резервна копія створена @@ -180,8 +179,6 @@ Видалити історію для записів, котрі не знаходяться в вашій бібліотеці Ви впевнені\? Прочитані розділи та прогрес не бібліотечних записів будуть втрачені Дані видалено - Оновити відстеження - Оновити стан, рахунок та останній розділ з каталогів, що відстежуються Версія Надсилати звіти про падіння Допомагає виправляти будь-які баги. Особисті дані не передаються @@ -574,8 +571,6 @@ Вимкнено Увімкнено Налаштування сортування для кожної категорії - Оновлювати відстежуване при оновлені бібліотеки - Автоматично оновлювати відстежуване Обмеження %s Локальне джерело У вашій бібліотеці ще немає категорій. diff --git a/i18n/src/main/res/values-uz/strings.xml b/i18n/src/main/res/values-uz/strings.xml index 49882925d..1646c2213 100644 --- a/i18n/src/main/res/values-uz/strings.xml +++ b/i18n/src/main/res/values-uz/strings.xml @@ -183,8 +183,6 @@ Qismlar soni Qism boshlanmagan Kutubxona yangilanishida yangi muqova va ma\'lumotlarni tekshirish - Kuzatmalarni yangilash - Kutubxona yangilanishida kuzatmalarni yangilash Doim so\'rash Har toifa o\'z sozlamasiga ega Cheklangan toifalardagi qismlar yangilanmaydi, yoniq toifalarga kirsaham. diff --git a/i18n/src/main/res/values-vi/strings.xml b/i18n/src/main/res/values-vi/strings.xml index 9574dbd63..8d4a5e925 100644 --- a/i18n/src/main/res/values-vi/strings.xml +++ b/i18n/src/main/res/values-vi/strings.xml @@ -276,7 +276,6 @@ Khôi phục sao lưu Khôi phục thư viện từ tập tin sao lưu Nơi lưu trữ - Tự động sao lưu Lịch sao lưu Số sao lưu tối đa Sao lưu đã được tạo @@ -284,8 +283,6 @@ Bạn có muốn sao lưu không\? Khôi phục sao lưu Đang tạo bản sao lưu - Làm mới theo dõi - Cập nhật trạng thái, điểm số và chương cuối đã đọc từ dịch vụ theo dõi Nguồn cục bộ Khác Tìm kiếm toàn bộ… @@ -575,8 +572,6 @@ Không tìm thấy chương Bật Tắt - Cập nhật theo dõi khi cập nhật thư viện - Tự động làm mới theo dõi Hạn chế: %s Người dùng chưa có danh mục. Tính năng tối ưu hóa của MIUI phải được bật lên để việc sao lưu/khôi phục hoạt động tốt. diff --git a/i18n/src/main/res/values-zh-rCN/strings.xml b/i18n/src/main/res/values-zh-rCN/strings.xml index 60095fb4d..ce0c97f31 100644 --- a/i18n/src/main/res/values-zh-rCN/strings.xml +++ b/i18n/src/main/res/values-zh-rCN/strings.xml @@ -162,7 +162,6 @@ 还原备份 从备份文件中还原 备份路径 - 自动备份 备份频率 最大备份数 已创建备份 @@ -180,8 +179,6 @@ 删除未添加到书架的作品记录 你确定吗?不在书架中的作品的已读章节和进度将会丢失 数据已删除 - 更新进度记录 - 从记录平台更新阅读状态、评分和进度 版本 发送错误报告 协助我们修复错误,发送的错误报告不包含个人敏感信息 @@ -534,8 +531,6 @@ 排序依据 无效的章节格式 未找到章节 - 更新书架时一并更新进度记录平台 - 自动更新进度记录 限制:%s 本地图源 关闭 @@ -649,11 +644,11 @@ 年龄分级 版本 语言 - 阅读列表 - 想读列表 - 读完列表 - 未读完列表 - 稍后读列表 + 阅读中 + 计划读 + 已完结 + 已放弃 + 搁置中 仅在不按流量计费网络中 打不开最后阅读章节 自定义封面 @@ -798,4 +793,12 @@ 无法连接到 %s 图源设置 应用设置 + 解锁 %s + 分类排序 + 将作品移到底部 + 书架更新中…(%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 a570bf0a5..57c60af4d 100644 --- a/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/i18n/src/main/res/values-zh-rTW/strings.xml @@ -117,7 +117,6 @@ 建立備份 還原備份 備份位置 - 自動備份 備份頻率 已建立備份 還原成功 @@ -270,8 +269,6 @@ 最後閱畢的章節 最大備份保留數 您確定要這樣做嗎?未收藏的漫畫的閱讀進度和章節會被刪除 - 更新閱讀歷程 - 與歷程平台同步處理閱讀狀態、評分以及進度 新上架 歷程 閱讀中 @@ -534,8 +531,6 @@ 未找到章節 關閉 開啟 - 更新書櫃時一併更新歷程平台 - 自動重新整理歷程平台 限制:%s 排序 無效的章節格式 From 7457a18aee15ce7b2afd01fc5bc33f08baa2f6f1 Mon Sep 17 00:00:00 2001 From: Eshlender <35057681+e-shl@users.noreply.github.com> Date: Sun, 29 Oct 2023 00:46:10 +0500 Subject: [PATCH 21/66] Add icons for author and artist in MangaInfoHeader (#10079) * Mark author and artist * overall style * Clean up spacing --------- Co-authored-by: arkon --- .../manga/components/MangaInfoHeader.kt | 82 +++++++++++++------ 1 file changed, 55 insertions(+), 27 deletions(-) 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 35e0997e2..a88aa7a7e 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 @@ -24,8 +24,10 @@ import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Brush import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.HourglassEmpty +import androidx.compose.material.icons.filled.PersonOutline import androidx.compose.material.icons.filled.Warning import androidx.compose.material.icons.outlined.AttachMoney import androidx.compose.material.icons.outlined.Block @@ -459,6 +461,7 @@ private fun MangaAndSourceTitlesSmall( modifier = Modifier .fillMaxWidth() .padding(start = 16.dp, top = appBarPadding + 16.dp, end = 16.dp), + horizontalArrangement = Arrangement.spacedBy(16.dp), verticalAlignment = Alignment.CenterVertically, ) { MangaCover.Book( @@ -469,7 +472,9 @@ private fun MangaAndSourceTitlesSmall( contentDescription = stringResource(R.string.manga_cover), onClick = onCoverClick, ) - Column(modifier = Modifier.padding(start = 16.dp)) { + Column( + verticalArrangement = Arrangement.spacedBy(2.dp), + ) { Text( text = title.ifBlank { stringResource(R.string.unknown_title) }, style = MaterialTheme.typography.titleLarge, @@ -485,40 +490,63 @@ private fun MangaAndSourceTitlesSmall( onClick = { if (title.isNotBlank()) doSearch(title, true) }, ), ) + Spacer(modifier = Modifier.height(2.dp)) - Text( - text = author?.takeIf { it.isNotBlank() } - ?: stringResource(R.string.unknown_author), - style = MaterialTheme.typography.titleSmall, - modifier = Modifier - .secondaryItemAlpha() - .padding(top = 2.dp) - .clickableNoIndication( - onLongClick = { - if (!author.isNullOrBlank()) { - context.copyToClipboard( - author, - author, - ) - } - }, - onClick = { if (!author.isNullOrBlank()) doSearch(author, true) }, - ), - ) - if (!artist.isNullOrBlank() && author != artist) { + + Row( + modifier = Modifier.secondaryItemAlpha(), + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = Icons.Filled.PersonOutline, + contentDescription = null, + modifier = Modifier.size(16.dp), + ) Text( - text = artist, + text = author?.takeIf { it.isNotBlank() } + ?: stringResource(R.string.unknown_author), style = MaterialTheme.typography.titleSmall, modifier = Modifier - .secondaryItemAlpha() - .padding(top = 2.dp) .clickableNoIndication( - onLongClick = { context.copyToClipboard(artist, artist) }, - onClick = { doSearch(artist, true) }, + onLongClick = { + if (!author.isNullOrBlank()) { + context.copyToClipboard( + author, + author, + ) + } + }, + onClick = { if (!author.isNullOrBlank()) doSearch(author, true) }, ), ) } - Spacer(modifier = Modifier.height(4.dp)) + + if (!artist.isNullOrBlank() && author != artist) { + Row( + modifier = Modifier.secondaryItemAlpha(), + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = Icons.Filled.Brush, + contentDescription = null, + modifier = Modifier.size(16.dp), + ) + Text( + text = artist, + style = MaterialTheme.typography.titleSmall, + modifier = Modifier + .clickableNoIndication( + onLongClick = { context.copyToClipboard(artist, artist) }, + onClick = { doSearch(artist, true) }, + ), + ) + } + } + + Spacer(modifier = Modifier.height(2.dp)) + Row( modifier = Modifier.secondaryItemAlpha(), verticalAlignment = Alignment.CenterVertically, From 443d56f69bc1df515ed2edcd5b2936ed8710fb71 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 28 Oct 2023 16:21:45 -0400 Subject: [PATCH 22/66] Add option to flash white screen on page change in reader for e-ink displays Closes #2123 --- .../settings/screen/SettingsReaderScreen.kt | 5 +++ .../presentation/reader/DisplayRefreshHost.kt | 45 +++++++++++++++++++ .../reader/settings/GeneralSettingsPage.kt | 5 +++ .../tachiyomi/ui/reader/ReaderActivity.kt | 12 +++++ .../tachiyomi/ui/reader/ReaderViewModel.kt | 3 ++ .../ui/reader/setting/ReaderPreferences.kt | 2 + i18n/src/main/res/values/strings.xml | 2 + 7 files changed, 74 insertions(+) create mode 100644 app/src/main/java/eu/kanade/presentation/reader/DisplayRefreshHost.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 e4ac76681..750f8138d 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 @@ -64,6 +64,11 @@ object SettingsReaderScreen : SearchableSettings { pref = readerPref.pageTransitions(), title = stringResource(R.string.pref_page_transitions), ), + Preference.PreferenceItem.SwitchPreference( + pref = readerPref.flashOnPageChange(), + title = stringResource(R.string.pref_flash_page), + subtitle = stringResource(R.string.pref_flash_page_summ), + ), getDisplayGroup(readerPreferences = readerPref), getReadingGroup(readerPreferences = readerPref), getPagedGroup(readerPreferences = readerPref), diff --git a/app/src/main/java/eu/kanade/presentation/reader/DisplayRefreshHost.kt b/app/src/main/java/eu/kanade/presentation/reader/DisplayRefreshHost.kt new file mode 100644 index 000000000..018dbb948 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/reader/DisplayRefreshHost.kt @@ -0,0 +1,45 @@ +package eu.kanade.presentation.reader + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import kotlinx.coroutines.delay + +@Stable +class DisplayRefreshHost { + + internal var currentDisplayRefresh by mutableStateOf(false) + + fun flash() { + currentDisplayRefresh = true + } +} + +@Composable +fun DisplayRefreshHost( + hostState: DisplayRefreshHost, + modifier: Modifier = Modifier, +) { + val currentDisplayRefresh = hostState.currentDisplayRefresh + LaunchedEffect(currentDisplayRefresh) { + if (currentDisplayRefresh) { + delay(200) + hostState.currentDisplayRefresh = false + } + } + + if (currentDisplayRefresh) { + Canvas( + modifier = modifier.fillMaxSize(), + ) { + drawRect(Color.White) + } + } +} diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt index 8d165ec76..5fe65eb2f 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt @@ -68,4 +68,9 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) { label = stringResource(R.string.pref_page_transitions), pref = screenModel.preferences.pageTransitions(), ) + + CheckboxItem( + label = stringResource(R.string.pref_flash_page), + pref = screenModel.preferences.flashOnPageChange(), + ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 1b8784d1a..9580af393 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -43,6 +43,7 @@ import com.google.android.material.transition.platform.MaterialContainerTransfor import dev.chrisbanes.insetter.applyInsetter import eu.kanade.domain.base.BasePreferences import eu.kanade.presentation.reader.BrightnessOverlay +import eu.kanade.presentation.reader.DisplayRefreshHost import eu.kanade.presentation.reader.OrientationModeSelectDialog import eu.kanade.presentation.reader.PageIndicatorText import eu.kanade.presentation.reader.ReaderPageActionsDialog @@ -122,6 +123,7 @@ class ReaderActivity : BaseActivity() { private var menuToggleToast: Toast? = null private var readingModeToast: Toast? = null + private val displayRefreshHost = DisplayRefreshHost() private val windowInsetsController by lazy { WindowInsetsControllerCompat(window, binding.root) } @@ -197,6 +199,9 @@ class ReaderActivity : BaseActivity() { ReaderViewModel.Event.ReloadViewerChapters -> { viewModel.state.value.viewerChapters?.let(::setChapters) } + ReaderViewModel.Event.PageChanged -> { + displayRefreshHost.flash() + } is ReaderViewModel.Event.SetOrientation -> { setOrientation(event.orientation) } @@ -323,6 +328,7 @@ class ReaderActivity : BaseActivity() { val isHttpSource = viewModel.getSource() is HttpSource val isFullscreen by readerPreferences.fullscreen().collectAsState() + val flashOnPageChange by readerPreferences.flashOnPageChange().collectAsState() val cropBorderPaged by readerPreferences.cropBorders().collectAsState() val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() @@ -375,6 +381,12 @@ class ReaderActivity : BaseActivity() { value = state.brightnessOverlayValue, ) + if (flashOnPageChange) { + DisplayRefreshHost( + hostState = displayRefreshHost, + ) + } + val onDismissRequest = viewModel::closeDialog when (state.dialog) { is ReaderViewModel.Dialog.Loading -> { 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 d1c91b62a..201c2eaa3 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 @@ -429,6 +429,8 @@ class ReaderViewModel @JvmOverloads constructor( if (inDownloadRange) { downloadNextChapters() } + + eventChannel.trySend(Event.PageChanged) } private fun downloadNextChapters() { @@ -917,6 +919,7 @@ class ReaderViewModel @JvmOverloads constructor( sealed interface Event { data object ReloadViewerChapters : Event + data object PageChanged : Event data class SetOrientation(val orientation: Int) : Event data class SetCoverResult(val result: SetAsCoverResult) : Event 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 faf75d0ba..ab38911f8 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 @@ -13,6 +13,8 @@ class ReaderPreferences( fun pageTransitions() = preferenceStore.getBoolean("pref_enable_transitions_key", true) + fun flashOnPageChange() = preferenceStore.getBoolean("pref_reader_flash", false) + fun doubleTapAnimSpeed() = preferenceStore.getInt("pref_double_tap_anim_speed", 500) fun showPageNumber() = preferenceStore.getBoolean("pref_show_page_number_key", true) diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 76fa240b7..642f4ce7d 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -333,6 +333,8 @@ Double tap to zoom Show content in cutout area Animate page transitions + Flash white on page change + Reduces ghosting on e-ink displays Double tap animation speed Show page number Show reading mode From 4868dd2d03214d0b1307cb42abd3e0a4cb5e85c6 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 28 Oct 2023 17:18:42 -0400 Subject: [PATCH 23/66] Try to ensure that reader page error message is removed if image is loaded Maybe fixes #5687 --- .../presentation/reader/BrightnessOverlay.kt | 3 ++- .../tachiyomi/ui/reader/ReaderViewModel.kt | 3 ++- .../ui/reader/viewer/pager/PagerPageHolder.kt | 16 ++++++++++++---- .../reader/viewer/webtoon/WebtoonPageHolder.kt | 3 ++- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt b/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt index 144b8ea27..b945906a4 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/BrightnessOverlay.kt @@ -1,5 +1,6 @@ package eu.kanade.presentation.reader +import androidx.annotation.IntRange import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable @@ -10,7 +11,7 @@ import kotlin.math.abs @Composable fun BrightnessOverlay( - value: Int, + @IntRange(from = -100, to = 100) value: Int, ) { if (value >= 0) return 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 201c2eaa3..1c9e4578d 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 @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.reader import android.app.Application import android.net.Uri +import androidx.annotation.IntRange import androidx.compose.runtime.Immutable import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel @@ -900,7 +901,7 @@ class ReaderViewModel @JvmOverloads constructor( val viewer: Viewer? = null, val dialog: Dialog? = null, val menuVisible: Boolean = false, - val brightnessOverlayValue: Int = 0, + @IntRange(from = -100, to = 100) val brightnessOverlayValue: Int = 0, ) { val currentChapter: ReaderChapter? get() = viewerChapters?.currChapter diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt index e1fd80ff5..51e9652aa 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt @@ -109,7 +109,7 @@ class PagerPageHolder( */ private fun setQueued() { progressIndicator.show() - errorLayout?.root?.isVisible = false + removeErrorLayout() } /** @@ -117,7 +117,7 @@ class PagerPageHolder( */ private fun setLoading() { progressIndicator.show() - errorLayout?.root?.isVisible = false + removeErrorLayout() } /** @@ -125,7 +125,7 @@ class PagerPageHolder( */ private fun setDownloading() { progressIndicator.show() - errorLayout?.root?.isVisible = false + removeErrorLayout() } /** @@ -133,7 +133,6 @@ class PagerPageHolder( */ private suspend fun setImage() { progressIndicator.setProgress(0) - errorLayout?.root?.isVisible = false val streamFn = page.stream ?: return @@ -170,6 +169,7 @@ class PagerPageHolder( pageBackground = background } } + removeErrorLayout() } } @@ -280,4 +280,12 @@ class PagerPageHolder( errorLayout?.root?.isVisible = true return errorLayout!! } + + /** + * Removes the decode error layout from the holder, if found. + */ + private fun removeErrorLayout() { + errorLayout?.root?.isVisible = false + errorLayout = null + } } 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 7fa2058d6..aeb25d905 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 @@ -181,7 +181,6 @@ class WebtoonPageHolder( */ private suspend fun setImage() { progressIndicator.setProgress(0) - removeErrorLayout() val streamFn = page?.stream ?: return @@ -202,6 +201,7 @@ class WebtoonPageHolder( cropBorders = viewer.config.imageCropBorders, ), ) + removeErrorLayout() } // Suspend the coroutine to close the input stream only when the WebtoonPageHolder is recycled suspendCancellableCoroutine { continuation -> @@ -234,6 +234,7 @@ class WebtoonPageHolder( */ private fun onImageDecoded() { progressContainer.isVisible = false + removeErrorLayout() } /** From 64ad25d1b5cd68457d36fda67d96f99812a53528 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 28 Oct 2023 22:41:35 -0400 Subject: [PATCH 24/66] Make scrollbar slightly chonkier Closes #9728 --- .../presentation/core/components/VerticalFastScroller.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 4f44f60e2..03380180e 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 @@ -350,7 +350,6 @@ fun VerticalGridFastScroller( }, ) .height(ThumbLength) - .padding(horizontal = 8.dp) .padding(end = endContentPadding) .width(ThumbThickness) .alpha(alpha.value) @@ -427,7 +426,7 @@ object Scroller { } private val ThumbLength = 48.dp -private val ThumbThickness = 8.dp +private val ThumbThickness = 12.dp private val ThumbShape = RoundedCornerShape(ThumbThickness / 2) private val FadeOutAnimationSpec = tween( durationMillis = ViewConfiguration.getScrollBarFadeDuration(), From ce5e10be955d8166f53de8118f8f12e76546b5ea Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 29 Oct 2023 11:43:06 -0400 Subject: [PATCH 25/66] Clean up chapter restoring logic a bit --- .../java/eu/kanade/domain/DomainModule.kt | 4 +- .../interactor/SyncChaptersWithSource.kt | 6 +-- .../eu/kanade/domain/chapter/model/Chapter.kt | 11 ----- .../SyncChapterProgressWithTrack.kt | 6 +-- .../tachiyomi/data/backup/BackupRestorer.kt | 40 ++++++++++++------- .../tachiyomi/data/track/BaseTracker.kt | 4 +- .../browse/migration/search/MigrateDialog.kt | 8 ++-- .../ui/library/LibraryScreenModel.kt | 4 +- .../tachiyomi/ui/reader/ReaderViewModel.kt | 6 +-- ...erByMangaId.kt => GetChaptersByMangaId.kt} | 2 +- .../tachiyomi/domain/chapter/model/Chapter.kt | 10 +++++ .../history/interactor/GetNextChapters.kt | 6 +-- .../domain/manga/interactor/FetchInterval.kt | 6 +-- 13 files changed, 61 insertions(+), 52 deletions(-) rename domain/src/main/java/tachiyomi/domain/chapter/interactor/{GetChapterByMangaId.kt => GetChaptersByMangaId.kt} (94%) diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 8559cd923..9967e000f 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -40,8 +40,8 @@ import tachiyomi.domain.category.interactor.SetSortModeForCategory import tachiyomi.domain.category.interactor.UpdateCategory import tachiyomi.domain.category.repository.CategoryRepository import tachiyomi.domain.chapter.interactor.GetChapter -import tachiyomi.domain.chapter.interactor.GetChapterByMangaId import tachiyomi.domain.chapter.interactor.GetChapterByUrlAndMangaId +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.chapter.interactor.SetMangaDefaultChapterFlags import tachiyomi.domain.chapter.interactor.ShouldUpdateDbChapter import tachiyomi.domain.chapter.interactor.UpdateChapter @@ -128,7 +128,7 @@ class DomainModule : InjektModule { addSingletonFactory { ChapterRepositoryImpl(get()) } addFactory { GetChapter(get()) } - addFactory { GetChapterByMangaId(get()) } + addFactory { GetChaptersByMangaId(get()) } addFactory { GetChapterByUrlAndMangaId(get()) } addFactory { UpdateChapter(get()) } addFactory { SetReadStatus(get(), get(), get(), get()) } diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt index 6205ea365..d233406f0 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt @@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.online.HttpSource import tachiyomi.data.chapter.ChapterSanitizer -import tachiyomi.domain.chapter.interactor.GetChapterByMangaId +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.chapter.interactor.ShouldUpdateDbChapter import tachiyomi.domain.chapter.interactor.UpdateChapter import tachiyomi.domain.chapter.model.Chapter @@ -32,7 +32,7 @@ class SyncChaptersWithSource( private val shouldUpdateDbChapter: ShouldUpdateDbChapter, private val updateManga: UpdateManga, private val updateChapter: UpdateChapter, - private val getChapterByMangaId: GetChapterByMangaId, + private val getChaptersByMangaId: GetChaptersByMangaId, ) { /** @@ -66,7 +66,7 @@ class SyncChaptersWithSource( } // Chapters from db. - val dbChapters = getChapterByMangaId.await(manga.id) + val dbChapters = getChaptersByMangaId.await(manga.id) // Chapters from the source not in db. val toAdd = mutableListOf() diff --git a/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt b/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt index af99f0e63..a852e1ae1 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt @@ -2,7 +2,6 @@ package eu.kanade.domain.chapter.model import eu.kanade.tachiyomi.data.database.models.ChapterImpl import eu.kanade.tachiyomi.source.model.SChapter -import tachiyomi.data.Chapters import tachiyomi.domain.chapter.model.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter as DbChapter @@ -27,16 +26,6 @@ fun Chapter.copyFromSChapter(sChapter: SChapter): Chapter { ) } -fun Chapter.copyFrom(other: Chapters): Chapter { - return copy( - name = other.name, - url = other.url, - dateUpload = other.date_upload, - chapterNumber = other.chapter_number, - scanlator = other.scanlator?.ifBlank { null }, - ) -} - fun Chapter.toDbChapter(): DbChapter = ChapterImpl().also { it.id = id it.manga_id = mangaId diff --git a/app/src/main/java/eu/kanade/domain/track/interactor/SyncChapterProgressWithTrack.kt b/app/src/main/java/eu/kanade/domain/track/interactor/SyncChapterProgressWithTrack.kt index dcb95ff26..6fab0792a 100644 --- a/app/src/main/java/eu/kanade/domain/track/interactor/SyncChapterProgressWithTrack.kt +++ b/app/src/main/java/eu/kanade/domain/track/interactor/SyncChapterProgressWithTrack.kt @@ -5,7 +5,7 @@ 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 +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.chapter.interactor.UpdateChapter import tachiyomi.domain.chapter.model.toChapterUpdate import tachiyomi.domain.track.interactor.InsertTrack @@ -14,7 +14,7 @@ import tachiyomi.domain.track.model.Track class SyncChapterProgressWithTrack( private val updateChapter: UpdateChapter, private val insertTrack: InsertTrack, - private val getChapterByMangaId: GetChapterByMangaId, + private val getChaptersByMangaId: GetChaptersByMangaId, ) { suspend fun await( @@ -26,7 +26,7 @@ class SyncChapterProgressWithTrack( return } - val sortedChapters = getChapterByMangaId.await(mangaId) + val sortedChapters = getChaptersByMangaId.await(mangaId) .sortedBy { it.chapterNumber } .filter { it.isRecognizedNumber } 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 ec34ce08a..753c3ef8e 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,7 +2,6 @@ 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 @@ -31,6 +30,7 @@ import tachiyomi.data.Manga_sync import tachiyomi.data.Mangas import tachiyomi.data.UpdateStrategyColumnAdapter import tachiyomi.domain.category.interactor.GetCategories +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.history.model.HistoryUpdate import tachiyomi.domain.library.service.LibraryPreferences @@ -54,6 +54,7 @@ class BackupRestorer( private val handler: DatabaseHandler = Injekt.get() private val updateManga: UpdateManga = Injekt.get() private val getCategories: GetCategories = Injekt.get() + private val getChaptersByMangaId: GetChaptersByMangaId = Injekt.get() private val fetchInterval: FetchInterval = Injekt.get() private val preferenceStore: PreferenceStore = Injekt.get() @@ -285,30 +286,39 @@ class BackupRestorer( } private suspend fun restoreChapters(manga: Manga, chapters: List) { - val dbChapters = handler.awaitList { chaptersQueries.getChaptersByMangaId(manga.id) } + val dbChaptersByUrl = getChaptersByMangaId.await(manga.id) + .associateBy { it.url } val processed = chapters.map { chapter -> var updatedChapter = chapter - val dbChapter = dbChapters.find { it.url == updatedChapter.url } + + val dbChapter = dbChaptersByUrl[updatedChapter.url] if (dbChapter != null) { - updatedChapter = updatedChapter.copy(id = dbChapter._id) - updatedChapter = updatedChapter.copyFrom(dbChapter) + updatedChapter = updatedChapter + .copyFrom(dbChapter) + .copy( + id = dbChapter.id, + mangaId = manga.id, + bookmark = updatedChapter.bookmark || dbChapter.bookmark, + ) 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 = updatedChapter.copy( + read = true, + lastPageRead = dbChapter.lastPageRead, + ) + } else if (updatedChapter.lastPageRead == 0L && dbChapter.lastPageRead != 0L) { + updatedChapter = updatedChapter.copy( + lastPageRead = dbChapter.lastPageRead, + ) } } - updatedChapter.copy(mangaId = manga.id) + updatedChapter } - val newChapters = processed.groupBy { it.id > 0 } - newChapters[true]?.let { updateKnownChapters(it) } - newChapters[false]?.let { insertChapters(it) } + val (existingChapters, newChapters) = processed.partition { it.id > 0 } + updateKnownChapters(existingChapters) + insertChapters(newChapters) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt index 8b152d6cb..94b81783d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt @@ -15,7 +15,7 @@ import okhttp3.OkHttpClient import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.system.logcat -import tachiyomi.domain.chapter.interactor.GetChapterByMangaId +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.history.interactor.GetHistory import tachiyomi.domain.track.interactor.InsertTrack import uy.kohesive.injekt.Injekt @@ -71,7 +71,7 @@ abstract class BaseTracker( item.manga_id = mangaId try { withIOContext { - val allChapters = Injekt.get().await(mangaId) + val allChapters = Injekt.get().await(mangaId) val hasReadChapters = allChapters.any { it.read } bind(item, hasReadChapters) 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 26bad6a5f..1eddff26d 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 @@ -41,7 +41,7 @@ import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.withUIContext import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.interactor.SetMangaCategories -import tachiyomi.domain.chapter.interactor.GetChapterByMangaId +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.chapter.interactor.UpdateChapter import tachiyomi.domain.chapter.model.toChapterUpdate import tachiyomi.domain.manga.model.Manga @@ -150,7 +150,7 @@ internal class MigrateDialogScreenModel( private val sourceManager: SourceManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), - private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(), + private val getChaptersByMangaId: GetChaptersByMangaId = Injekt.get(), private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(), private val updateChapter: UpdateChapter = Injekt.get(), private val getCategories: GetCategories = Injekt.get(), @@ -222,8 +222,8 @@ internal class MigrateDialogScreenModel( // Update chapters read, bookmark and dateFetch if (migrateChapters) { - val prevMangaChapters = getChapterByMangaId.await(oldManga.id) - val mangaChapters = getChapterByMangaId.await(newManga.id) + val prevMangaChapters = getChaptersByMangaId.await(oldManga.id) + val mangaChapters = getChaptersByMangaId.await(newManga.id) val maxChapterRead = prevMangaChapters .filter { it.read } 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 6d16364c3..af0f5c81a 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 @@ -47,7 +47,7 @@ import tachiyomi.core.util.lang.withIOContext import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.interactor.SetMangaCategories import tachiyomi.domain.category.model.Category -import tachiyomi.domain.chapter.interactor.GetChapterByMangaId +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.history.interactor.GetNextChapters import tachiyomi.domain.library.model.LibraryDisplayMode @@ -78,7 +78,7 @@ class LibraryScreenModel( private val getCategories: GetCategories = Injekt.get(), private val getTracksPerManga: GetTracksPerManga = Injekt.get(), private val getNextChapters: GetNextChapters = Injekt.get(), - private val getChaptersByMangaId: GetChapterByMangaId = Injekt.get(), + private val getChaptersByMangaId: GetChaptersByMangaId = Injekt.get(), private val setReadStatus: SetReadStatus = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), private val setMangaCategories: SetMangaCategories = Injekt.get(), 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 1c9e4578d..c0a252b35 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 @@ -60,7 +60,7 @@ import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.system.logcat -import tachiyomi.domain.chapter.interactor.GetChapterByMangaId +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.chapter.interactor.UpdateChapter import tachiyomi.domain.chapter.model.ChapterUpdate import tachiyomi.domain.chapter.service.getChapterSort @@ -92,7 +92,7 @@ class ReaderViewModel @JvmOverloads constructor( private val trackPreferences: TrackPreferences = Injekt.get(), private val trackChapter: TrackChapter = Injekt.get(), private val getManga: GetManga = Injekt.get(), - private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(), + private val getChaptersByMangaId: GetChaptersByMangaId = Injekt.get(), private val getNextChapters: GetNextChapters = Injekt.get(), private val upsertHistory: UpsertHistory = Injekt.get(), private val updateChapter: UpdateChapter = Injekt.get(), @@ -147,7 +147,7 @@ class ReaderViewModel @JvmOverloads constructor( */ private val chapterList by lazy { val manga = manga!! - val chapters = runBlocking { getChapterByMangaId.await(manga.id) } + val chapters = runBlocking { getChaptersByMangaId.await(manga.id) } val selectedChapter = chapters.find { it.id == chapterId } ?: error("Requested chapter of id $chapterId not found in chapter list") diff --git a/domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChapterByMangaId.kt b/domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChaptersByMangaId.kt similarity index 94% rename from domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChapterByMangaId.kt rename to domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChaptersByMangaId.kt index fb7350892..6dcc0d32b 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChapterByMangaId.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChaptersByMangaId.kt @@ -5,7 +5,7 @@ import tachiyomi.core.util.system.logcat import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.repository.ChapterRepository -class GetChapterByMangaId( +class GetChaptersByMangaId( private val chapterRepository: ChapterRepository, ) { diff --git a/domain/src/main/java/tachiyomi/domain/chapter/model/Chapter.kt b/domain/src/main/java/tachiyomi/domain/chapter/model/Chapter.kt index 0029d67ea..3a4a8c4a4 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/model/Chapter.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/model/Chapter.kt @@ -18,6 +18,16 @@ data class Chapter( val isRecognizedNumber: Boolean get() = chapterNumber >= 0f + fun copyFrom(other: Chapter): Chapter { + return copy( + name = other.name, + url = other.url, + dateUpload = other.dateUpload, + chapterNumber = other.chapterNumber, + scanlator = other.scanlator?.ifBlank { null }, + ) + } + companion object { fun create() = Chapter( id = -1, 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 6e9526158..2cbda1bdf 100644 --- a/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt +++ b/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt @@ -1,6 +1,6 @@ package tachiyomi.domain.history.interactor -import tachiyomi.domain.chapter.interactor.GetChapterByMangaId +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.service.getChapterSort import tachiyomi.domain.history.repository.HistoryRepository @@ -8,7 +8,7 @@ import tachiyomi.domain.manga.interactor.GetManga import kotlin.math.max class GetNextChapters( - private val getChapterByMangaId: GetChapterByMangaId, + private val getChaptersByMangaId: GetChaptersByMangaId, private val getManga: GetManga, private val historyRepository: HistoryRepository, ) { @@ -20,7 +20,7 @@ class GetNextChapters( suspend fun await(mangaId: Long, onlyUnread: Boolean = true): List { val manga = getManga.await(mangaId) ?: return emptyList() - val chapters = getChapterByMangaId.await(mangaId) + val chapters = getChaptersByMangaId.await(mangaId) .sortedWith(getChapterSort(manga, sortDescending = false)) return if (onlyUnread) { diff --git a/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt b/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt index 740c0a150..308ed8bf6 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt @@ -1,6 +1,6 @@ package tachiyomi.domain.manga.interactor -import tachiyomi.domain.chapter.interactor.GetChapterByMangaId +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.MangaUpdate @@ -11,7 +11,7 @@ import java.time.temporal.ChronoUnit import kotlin.math.absoluteValue class FetchInterval( - private val getChapterByMangaId: GetChapterByMangaId, + private val getChaptersByMangaId: GetChaptersByMangaId, ) { suspend fun toMangaUpdateOrNull( @@ -24,7 +24,7 @@ class FetchInterval( } else { window } - val chapters = getChapterByMangaId.await(manga.id) + val chapters = getChaptersByMangaId.await(manga.id) val interval = manga.fetchInterval.takeIf { it < 0 } ?: calculateInterval( chapters, dateTime.zone, From 298c49f3ab7000ed0457aa177bba9a98072b1339 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 29 Oct 2023 11:54:50 -0400 Subject: [PATCH 26/66] Abstract out library last updated timespan text So we can reuse it for showing last automatic backup time. --- .../presentation/updates/UpdatesScreen.kt | 4 +--- .../presentation/updates/UpdatesUiItem.kt | 20 ++----------------- .../util/{DurationUtils.kt => TimeUtils.kt} | 17 ++++++++++++++++ i18n/src/main/res/values/strings.xml | 1 + 4 files changed, 21 insertions(+), 21 deletions(-) rename app/src/main/java/eu/kanade/presentation/util/{DurationUtils.kt => TimeUtils.kt} (51%) 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 1572faff4..5391d56bb 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt @@ -109,9 +109,7 @@ fun UpdateScreen( FastScrollLazyColumn( contentPadding = contentPadding, ) { - if (lastUpdated > 0L) { - updatesLastUpdatedItem(lastUpdated) - } + updatesLastUpdatedItem(lastUpdated) updatesUiItems( uiModels = state.getUiModel(context, relativeTime), diff --git a/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt b/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt index 50ef6840b..9be12b6bb 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt @@ -1,6 +1,5 @@ package eu.kanade.presentation.updates -import android.text.format.DateUtils import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -27,7 +26,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalHapticFeedback @@ -39,6 +37,7 @@ import eu.kanade.presentation.manga.components.ChapterDownloadAction import eu.kanade.presentation.manga.components.ChapterDownloadIndicator import eu.kanade.presentation.manga.components.DotSeparatorText import eu.kanade.presentation.manga.components.MangaCover +import eu.kanade.presentation.util.relativeTimeSpanString import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.ui.updates.UpdatesItem @@ -47,33 +46,18 @@ import tachiyomi.presentation.core.components.ListGroupHeader import tachiyomi.presentation.core.components.material.ReadItemAlpha import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.util.selectedBackground -import java.util.Date -import kotlin.time.Duration.Companion.minutes internal fun LazyListScope.updatesLastUpdatedItem( lastUpdated: Long, ) { item(key = "updates-lastUpdated") { - val time = remember(lastUpdated) { - val now = Date().time - if (now - lastUpdated < 1.minutes.inWholeMilliseconds) { - null - } else { - DateUtils.getRelativeTimeSpanString(lastUpdated, now, DateUtils.MINUTE_IN_MILLIS) - } - } - Box( modifier = Modifier .animateItemPlacement() .padding(horizontal = MaterialTheme.padding.medium, vertical = MaterialTheme.padding.small), ) { Text( - text = if (time.isNullOrEmpty()) { - stringResource(R.string.updates_last_update_info, stringResource(R.string.updates_last_update_info_just_now)) - } else { - stringResource(R.string.updates_last_update_info, time) - }, + text = stringResource(R.string.updates_last_update_info, relativeTimeSpanString(lastUpdated)), fontStyle = FontStyle.Italic, ) } diff --git a/app/src/main/java/eu/kanade/presentation/util/DurationUtils.kt b/app/src/main/java/eu/kanade/presentation/util/TimeUtils.kt similarity index 51% rename from app/src/main/java/eu/kanade/presentation/util/DurationUtils.kt rename to app/src/main/java/eu/kanade/presentation/util/TimeUtils.kt index 644f5ca13..e98374fd8 100644 --- a/app/src/main/java/eu/kanade/presentation/util/DurationUtils.kt +++ b/app/src/main/java/eu/kanade/presentation/util/TimeUtils.kt @@ -1,8 +1,14 @@ package eu.kanade.presentation.util import android.content.Context +import android.text.format.DateUtils +import androidx.compose.runtime.Composable +import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.ui.res.stringResource import eu.kanade.tachiyomi.R +import java.util.Date import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes fun Duration.toDurationString(context: Context, fallback: String): String { return toComponents { days, hours, minutes, seconds, _ -> @@ -14,3 +20,14 @@ fun Duration.toDurationString(context: Context, fallback: String): String { }.joinToString(" ").ifBlank { fallback } } } + +@Composable +@ReadOnlyComposable +fun relativeTimeSpanString(epochMillis: Long): String { + val now = Date().time + return when { + epochMillis <= 0L -> stringResource(R.string.relative_time_span_never) + now - epochMillis < 1.minutes.inWholeMilliseconds -> stringResource(R.string.updates_last_update_info_just_now) + else -> DateUtils.getRelativeTimeSpanString(epochMillis, now, DateUtils.MINUTE_IN_MILLIS).toString() + } +} diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 642f4ce7d..7085c9d4c 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -782,6 +782,7 @@ Unable to open last read chapter Library last updated: %s Just now + Never Ch. %1$s - %2$s From 1aa5222c99f50543c47d5f3bd4bb892e16e31efb Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 29 Oct 2023 12:03:46 -0400 Subject: [PATCH 27/66] Record time when last automatic backup was created Closes #3474 --- .../more/settings/screen/SettingsDataScreen.kt | 7 ++++++- .../eu/kanade/tachiyomi/data/backup/BackupCreateJob.kt | 7 ++++++- .../tachiyomi/domain/backup/service/BackupPreferences.kt | 3 +++ i18n/src/main/res/values/strings.xml | 1 + 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt index 75c1cf467..1f21a3261 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt @@ -33,6 +33,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.permissions.PermissionRequestHelper +import eu.kanade.presentation.util.relativeTimeSpanString import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.BackupConst import eu.kanade.tachiyomi.data.backup.BackupCreateJob @@ -82,6 +83,7 @@ object SettingsDataScreen : SearchableSettings { val context = LocalContext.current val backupIntervalPref = backupPreferences.backupInterval() val backupInterval by backupIntervalPref.collectAsState() + val lastAutoBackup by backupPreferences.lastAutoBackupTimestamp().collectAsState() return Preference.PreferenceGroup( title = stringResource(R.string.label_backup), @@ -113,7 +115,10 @@ object SettingsDataScreen : SearchableSettings { title = stringResource(R.string.pref_backup_slots), entries = listOf(2, 3, 4, 5).associateWith { it.toString() }, ), - Preference.PreferenceItem.InfoPreference(stringResource(R.string.backup_info)), + Preference.PreferenceItem.InfoPreference( + stringResource(R.string.backup_info) + "\n\n" + + stringResource(R.string.last_auto_backup_info, relativeTimeSpanString(lastAutoBackup)), + ), ), ) } 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 875039e86..d46a58e00 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 @@ -23,6 +23,7 @@ import tachiyomi.core.util.system.logcat import tachiyomi.domain.backup.service.BackupPreferences import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import java.util.Date import java.util.concurrent.TimeUnit import kotlin.time.Duration.Companion.minutes import kotlin.time.toJavaDuration @@ -50,7 +51,11 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete return try { val location = BackupCreator(context).createBackup(uri, flags, isAutoBackup) - if (!isAutoBackup) notifier.showBackupComplete(UniFile.fromUri(context, location.toUri())) + if (isAutoBackup) { + backupPreferences.lastAutoBackupTimestamp().set(Date().time) + } else { + notifier.showBackupComplete(UniFile.fromUri(context, location.toUri())) + } Result.success() } catch (e: Exception) { logcat(LogPriority.ERROR, e) diff --git a/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt b/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt index 0f6616338..e0f96dffa 100644 --- a/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt @@ -13,4 +13,7 @@ class BackupPreferences( fun numberOfBackups() = preferenceStore.getInt("backup_slots", 2) fun backupInterval() = preferenceStore.getInt("backup_interval", 12) + + // TODO: move this and other "app state" preferences elsewhere and exclude from backups + fun lastAutoBackupTimestamp() = preferenceStore.getLong("__APP_STATE_last_auto_backup_timestamp", 0L) } diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 7085c9d4c..6e33f1f7f 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -505,6 +505,7 @@ Restoring backup failed Canceled restore You should keep copies of backups in other places as well. Backups may contain sensitive data including any stored passwords; be careful if sharing. + Last automatically backed up: %s Syncing library From ce7bf396ebc0b85d0e857c55b27cb5eab2ad9d5b Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 29 Oct 2023 12:24:02 -0400 Subject: [PATCH 28/66] Don't include "app state" preferences in backups --- app/build.gradle.kts | 2 +- .../eu/kanade/domain/base/BasePreferences.kt | 8 ++- .../source/service/SourcePreferences.kt | 8 ++- .../java/eu/kanade/tachiyomi/Migrations.kt | 71 ++++++++++++++++--- .../tachiyomi/data/backup/BackupCreator.kt | 4 +- .../core/security/SecurityPreferences.kt | 6 +- .../tachiyomi/core/preference/Preference.kt | 18 +++-- .../backup/service/BackupPreferences.kt | 4 +- .../library/service/LibraryPreferences.kt | 7 +- 9 files changed, 100 insertions(+), 28 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2e59bec8f..3d120e8aa 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,7 +22,7 @@ android { defaultConfig { applicationId = "eu.kanade.tachiyomi" - versionCode = 107 + versionCode = 108 versionName = "0.14.7" buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") diff --git a/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt b/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt index 34ef79b48..0acef84a9 100644 --- a/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt @@ -5,6 +5,7 @@ import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.isPreviewBuildType import eu.kanade.tachiyomi.util.system.isReleaseBuildType +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore class BasePreferences( @@ -12,9 +13,12 @@ class BasePreferences( private val preferenceStore: PreferenceStore, ) { - fun downloadedOnly() = preferenceStore.getBoolean("pref_downloaded_only", false) + fun downloadedOnly() = preferenceStore.getBoolean( + Preference.appStateKey("pref_downloaded_only"), + false, + ) - fun incognitoMode() = preferenceStore.getBoolean("incognito_mode", false) + fun incognitoMode() = preferenceStore.getBoolean(Preference.appStateKey("incognito_mode"), false) fun extensionInstaller() = ExtensionInstallerPreference(context, preferenceStore) diff --git a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt index 582dd61d7..67f5c3190 100644 --- a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt @@ -2,6 +2,7 @@ package eu.kanade.domain.source.service import eu.kanade.domain.source.interactor.SetMigrateSorting import eu.kanade.tachiyomi.util.system.LocaleHelper +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.getEnum import tachiyomi.domain.library.model.LibraryDisplayMode @@ -18,7 +19,10 @@ class SourcePreferences( fun pinnedSources() = preferenceStore.getStringSet("pinned_catalogues", emptySet()) - fun lastUsedSource() = preferenceStore.getLong("last_catalogue_source", -1) + fun lastUsedSource() = preferenceStore.getLong( + Preference.appStateKey("last_catalogue_source"), + -1, + ) fun showNsfwSource() = preferenceStore.getBoolean("show_nsfw_source", true) @@ -28,7 +32,7 @@ class SourcePreferences( fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0) - fun trustedSignatures() = preferenceStore.getStringSet("trusted_signatures", emptySet()) + fun trustedSignatures() = preferenceStore.getStringSet(Preference.appStateKey("trusted_signatures"), emptySet()) fun hideInLibraryItems() = preferenceStore.getBoolean("browse_hide_in_library_items", false) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index bbdcaa6ea..b1cbe9d27 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -375,17 +375,28 @@ object Migrations { } } 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() - } - } + replacePreferences( + preferenceStore = preferenceStore, + filterPredicate = { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") }, + newKey = { Preference.privateKey(it) }, + ) + } + if (oldVersion < 108) { + val prefsToReplace = listOf( + "pref_download_only", + "incognito_mode", + "last_catalogue_source", + "trusted_signatures", + "last_app_closed", + "library_update_last_timestamp", + "library_unseen_updates_count", + "last_used_category", + ) + replacePreferences( + preferenceStore = preferenceStore, + filterPredicate = { it.key in prefsToReplace }, + newKey = { Preference.appStateKey(it) }, + ) } return true } @@ -393,3 +404,41 @@ object Migrations { return false } } + +@Suppress("UNCHECKED_CAST") +private fun replacePreferences( + preferenceStore: PreferenceStore, + filterPredicate: (Map.Entry) -> Boolean, + newKey: (String) -> String, +) { + preferenceStore.getAll() + .filter(filterPredicate) + .forEach { (key, value) -> + when (value) { + is Int -> { + preferenceStore.getInt(newKey(key)).set(value) + preferenceStore.getInt(key).delete() + } + is Long -> { + preferenceStore.getLong(newKey(key)).set(value) + preferenceStore.getLong(key).delete() + } + is Float -> { + preferenceStore.getFloat(newKey(key)).set(value) + preferenceStore.getFloat(key).delete() + } + is String -> { + preferenceStore.getString(newKey(key)).set(value) + preferenceStore.getString(key).delete() + } + is Boolean -> { + preferenceStore.getBoolean(newKey(key)).set(value) + preferenceStore.getBoolean(key).delete() + } + is Set<*> -> (value as? Set)?.let { + preferenceStore.getStringSet(newKey(key)).set(value) + preferenceStore.getStringSet(key).delete() + } + } + } +} 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 index ef8704b02..37c9e73f0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt @@ -250,7 +250,9 @@ class BackupCreator( @Suppress("UNCHECKED_CAST") private fun Map.toBackupPreferences(): List { - return this.filterKeys { !Preference.isPrivate(it) } + return this.filterKeys { + !Preference.isPrivate(it) && !Preference.isAppState(it) + } .mapNotNull { (key, value) -> when (value) { is Int -> BackupPreference(key, IntPreferenceValue(value)) diff --git a/core/src/main/java/eu/kanade/tachiyomi/core/security/SecurityPreferences.kt b/core/src/main/java/eu/kanade/tachiyomi/core/security/SecurityPreferences.kt index 371bd776b..f27b1a44c 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/core/security/SecurityPreferences.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/core/security/SecurityPreferences.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.core.security import eu.kanade.tachiyomi.core.R +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.getEnum @@ -20,7 +21,10 @@ class SecurityPreferences( * For app lock. Will be set when there is a pending timed lock. * Otherwise this pref should be deleted. */ - fun lastAppClosed() = preferenceStore.getLong("last_app_closed", 0) + fun lastAppClosed() = preferenceStore.getLong( + Preference.appStateKey("last_app_closed"), + 0, + ) enum class SecureScreenMode(val titleResId: Int) { ALWAYS(R.string.lock_always), diff --git a/core/src/main/java/tachiyomi/core/preference/Preference.kt b/core/src/main/java/tachiyomi/core/preference/Preference.kt index e10f6e7fe..bd95798ef 100644 --- a/core/src/main/java/tachiyomi/core/preference/Preference.kt +++ b/core/src/main/java/tachiyomi/core/preference/Preference.kt @@ -22,21 +22,29 @@ interface Preference { 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. + * A preference that should not be exposed in places like backups without user consent. */ fun isPrivate(key: String): Boolean { return key.startsWith(PRIVATE_PREFIX) } - fun privateKey(key: String): String { return "${PRIVATE_PREFIX}$key" } + /** + * A preference used for internal app state that isn't really a user preference + * and therefore should not be inplaces like backips. + */ + fun isAppState(key: String): Boolean { + return key.startsWith(APP_STATE_PREFIX) + } + fun appStateKey(key: String): String { + return "${APP_STATE_PREFIX}$key" + } + + private const val APP_STATE_PREFIX = "__APP_STATE_" private const val PRIVATE_PREFIX = "__PRIVATE_" } } diff --git a/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt b/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt index e0f96dffa..e923b2daa 100644 --- a/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt @@ -1,5 +1,6 @@ package tachiyomi.domain.backup.service +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.provider.FolderProvider @@ -14,6 +15,5 @@ class BackupPreferences( fun backupInterval() = preferenceStore.getInt("backup_interval", 12) - // TODO: move this and other "app state" preferences elsewhere and exclude from backups - fun lastAutoBackupTimestamp() = preferenceStore.getLong("__APP_STATE_last_auto_backup_timestamp", 0L) + fun lastAutoBackupTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_auto_backup_timestamp"), 0L) } 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 8edfa7a27..1a51fa659 100644 --- a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt @@ -1,5 +1,6 @@ package tachiyomi.domain.library.service +import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.TriState import tachiyomi.core.preference.getEnum @@ -29,7 +30,7 @@ class LibraryPreferences( fun landscapeColumns() = preferenceStore.getInt("pref_library_columns_landscape_key", 0) - fun lastUpdatedTimestamp() = preferenceStore.getLong("library_update_last_timestamp", 0L) + fun lastUpdatedTimestamp() = preferenceStore.getLong(Preference.appStateKey("library_update_last_timestamp"), 0L) fun autoUpdateInterval() = preferenceStore.getInt("pref_library_update_interval_key", 0) fun autoUpdateDeviceRestrictions() = preferenceStore.getStringSet( @@ -120,7 +121,7 @@ class LibraryPreferences( fun languageBadge() = preferenceStore.getBoolean("display_language_badge", false) fun newShowUpdatesCount() = preferenceStore.getBoolean("library_show_updates_count", true) - fun newUpdatesCount() = preferenceStore.getInt("library_unseen_updates_count", 0) + fun newUpdatesCount() = preferenceStore.getInt(Preference.appStateKey("library_unseen_updates_count"), 0) // endregion @@ -128,7 +129,7 @@ class LibraryPreferences( fun defaultCategory() = preferenceStore.getInt("default_category", -1) - fun lastUsedCategory() = preferenceStore.getInt("last_used_category", 0) + fun lastUsedCategory() = preferenceStore.getInt(Preference.appStateKey("last_used_category"), 0) fun categoryTabs() = preferenceStore.getBoolean("display_category_tabs", true) From cb8ea5eab0ec68ea02e8dc98c0a52771c460d5ab Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 29 Oct 2023 16:57:38 -0400 Subject: [PATCH 29/66] Add basic storage usage info to "Data and storage" settings screen --- .../settings/screen/SettingsDataScreen.kt | 43 +++++++++++++++++-- .../kanade/tachiyomi/util/storage/DiskUtil.kt | 24 +++++++++++ .../tachiyomi/core/preference/Preference.kt | 2 +- i18n/src/main/res/values/strings.xml | 13 +++--- 4 files changed, 71 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt index 1f21a3261..c62c6c12a 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt @@ -4,12 +4,15 @@ import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent import android.net.Uri +import android.os.Environment +import android.text.format.Formatter import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.StringRes import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -32,6 +35,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import eu.kanade.presentation.more.settings.Preference +import eu.kanade.presentation.more.settings.widget.BasePreferenceWidget +import eu.kanade.presentation.more.settings.widget.PrefsHorizontalPadding import eu.kanade.presentation.permissions.PermissionRequestHelper import eu.kanade.presentation.util.relativeTimeSpanString import eu.kanade.tachiyomi.R @@ -41,6 +46,7 @@ import eu.kanade.tachiyomi.data.backup.BackupFileValidator import eu.kanade.tachiyomi.data.backup.BackupRestoreJob import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.cache.ChapterCache +import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.toast @@ -373,22 +379,24 @@ object SettingsDataScreen : SearchableSettings { val libraryPreferences = remember { Injekt.get() } val chapterCache = remember { Injekt.get() } - var readableSizeSema by remember { mutableIntStateOf(0) } - val readableSize = remember(readableSizeSema) { chapterCache.readableSize } + var cacheReadableSizeSema by remember { mutableIntStateOf(0) } + val cacheReadableSize = remember(cacheReadableSizeSema) { chapterCache.readableSize } return Preference.PreferenceGroup( title = stringResource(R.string.label_data), preferenceItems = listOf( + getStorageInfoPref(cacheReadableSize), + Preference.PreferenceItem.TextPreference( title = stringResource(R.string.pref_clear_chapter_cache), - subtitle = stringResource(R.string.used_cache, readableSize), + subtitle = stringResource(R.string.used_cache, cacheReadableSize), onClick = { scope.launchNonCancellable { try { val deletedFiles = chapterCache.clear() withUIContext { context.toast(context.getString(R.string.cache_deleted, deletedFiles)) - readableSizeSema++ + cacheReadableSizeSema++ } } catch (e: Throwable) { logcat(LogPriority.ERROR, e) @@ -404,6 +412,33 @@ object SettingsDataScreen : SearchableSettings { ), ) } + + @Composable + fun getStorageInfoPref( + chapterCacheReadableSize: String, + ): Preference.PreferenceItem.CustomPreference { + val context = LocalContext.current + val available = remember { + Formatter.formatFileSize(context, DiskUtil.getAvailableStorageSpace(Environment.getDataDirectory())) + } + val total = remember { + Formatter.formatFileSize(context, DiskUtil.getTotalStorageSpace(Environment.getDataDirectory())) + } + + return Preference.PreferenceItem.CustomPreference( + title = stringResource(R.string.pref_storage_usage), + ) { + BasePreferenceWidget( + title = stringResource(R.string.pref_storage_usage), + subcomponent = { + // TODO: downloads, SD cards, bar representation?, i18n + Box(modifier = Modifier.padding(horizontal = PrefsHorizontalPadding)) { + Text(text = "Available: $available / $total (chapter cache: $chapterCacheReadableSize)") + } + }, + ) + } + } } private data class MissingRestoreComponents( diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt b/core/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt index acddaf0bd..5ea61b5a5 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt @@ -28,6 +28,30 @@ object DiskUtil { return size } + /** + * Gets the total space for the disk that a file path points to, in bytes. + */ + fun getTotalStorageSpace(file: File): Long { + return try { + val stat = StatFs(file.absolutePath) + stat.blockCountLong * stat.blockSizeLong + } catch (_: Exception) { + -1L + } + } + + /** + * Gets the available space for the disk that a file path points to, in bytes. + */ + fun getAvailableStorageSpace(file: File): Long { + return try { + val stat = StatFs(file.absolutePath) + stat.availableBlocksLong * stat.blockSizeLong + } catch (_: Exception) { + -1L + } + } + /** * Gets the available space for the disk that a file path points to, in bytes. */ diff --git a/core/src/main/java/tachiyomi/core/preference/Preference.kt b/core/src/main/java/tachiyomi/core/preference/Preference.kt index bd95798ef..1cc0d3d3c 100644 --- a/core/src/main/java/tachiyomi/core/preference/Preference.kt +++ b/core/src/main/java/tachiyomi/core/preference/Preference.kt @@ -35,7 +35,7 @@ interface Preference { /** * A preference used for internal app state that isn't really a user preference - * and therefore should not be inplaces like backips. + * and therefore should not be in places like backups. */ fun isAppState(key: String): Boolean { return key.startsWith(APP_STATE_PREFIX) diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 6e33f1f7f..11df5d701 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -506,6 +506,13 @@ Canceled restore You should keep copies of backups in other places as well. Backups may contain sensitive data including any stored passwords; be careful if sharing. Last automatically backed up: %s + Data + Storage usage + Clear chapter cache + Used: %1$s + Cache cleared. %1$d files have been deleted + Error occurred while clearing + Clear chapter cache on app launch Syncing library @@ -521,12 +528,6 @@ Reset default user agent string Requires app restart to take effect Cookies cleared - Data - Clear chapter cache - Used: %1$s - Cache cleared. %1$d files have been deleted - Error occurred while clearing - Clear chapter cache on app launch Invalidate downloads index Force app to recheck downloaded chapters Downloads index invalidated From 7cf2ce29947e96a2eac011e48a92e1029e344831 Mon Sep 17 00:00:00 2001 From: arkon Date: Tue, 31 Oct 2023 18:03:07 -0400 Subject: [PATCH 30/66] Handle Brotli-compressed responses --- core/build.gradle.kts | 1 + .../src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt | 2 ++ gradle/libs.versions.toml | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index bfd8e4a88..d629d74dc 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -25,6 +25,7 @@ dependencies { api(libs.okhttp.core) api(libs.okhttp.logging) + api(libs.okhttp.brotli) api(libs.okhttp.dnsoverhttps) api(libs.okio) 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 6893a0495..f8f1a6395 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.network.interceptor.UncaughtExceptionInterceptor import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor import okhttp3.Cache import okhttp3.OkHttpClient +import okhttp3.brotli.BrotliInterceptor import okhttp3.logging.HttpLoggingInterceptor import java.io.File import java.util.concurrent.TimeUnit @@ -29,6 +30,7 @@ class NetworkHelper( maxSize = 5L * 1024 * 1024, // 5 MiB ), ) + .addInterceptor(BrotliInterceptor) .addInterceptor(UncaughtExceptionInterceptor()) .addInterceptor(UserAgentInterceptor(::defaultUserAgentProvider)) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c629087e..dfe6874e8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,6 +18,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-brotli = { module = "com.squareup.okhttp3:okhttp-brotli", version.ref = "okhttp_version" } okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp_version" } okio = "com.squareup.okio:okio:3.6.0" @@ -92,7 +93,7 @@ voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", vers ktlint = "org.jlleitschuh.gradle:ktlint-gradle:11.6.1" [bundles] -okhttp = ["okhttp-core", "okhttp-logging", "okhttp-dnsoverhttps"] +okhttp = ["okhttp-core", "okhttp-logging", "okhttp-brotli", "okhttp-dnsoverhttps"] js-engine = ["quickjs-android"] sqlite = ["sqlite-framework", "sqlite-ktx", "sqlite-android"] coil = ["coil-core", "coil-gif", "coil-compose"] From 2ee895ee3c09004666652181fedd653f4aeeb90f Mon Sep 17 00:00:00 2001 From: arkon Date: Tue, 31 Oct 2023 18:05:37 -0400 Subject: [PATCH 31/66] Use same icon as chapter list items to indicate downloaded chapter in reader transitions --- .../java/eu/kanade/presentation/reader/ChapterTransition.kt | 4 ++-- .../main/java/eu/kanade/presentation/track/TrackerSearch.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt b/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt index 0639e75d7..a153b37b1 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt @@ -11,8 +11,8 @@ import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.text.InlineTextContent import androidx.compose.foundation.text.appendInlineContent import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material.icons.outlined.Info -import androidx.compose.material.icons.outlined.OfflinePin import androidx.compose.material.icons.outlined.Warning import androidx.compose.material3.CardColors import androidx.compose.material3.CardDefaults @@ -244,7 +244,7 @@ private fun ChapterText( ), ) { Icon( - imageVector = Icons.Outlined.OfflinePin, + imageVector = Icons.Filled.CheckCircle, contentDescription = stringResource(R.string.label_downloaded), ) }, diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt index b1c3f2844..df11b1ce1 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt @@ -240,7 +240,7 @@ private fun SearchResultItem( ) { if (selected) { Icon( - imageVector = Icons.Default.CheckCircle, + imageVector = Icons.Filled.CheckCircle, contentDescription = null, modifier = Modifier.align(Alignment.TopEnd), tint = MaterialTheme.colorScheme.primary, From 8a1625ec7906a3f396d0f217cd8c168f539b5167 Mon Sep 17 00:00:00 2001 From: Howard Wu Date: Wed, 1 Nov 2023 10:14:31 +0800 Subject: [PATCH 32/66] buildDir deprecated, use layout.buildDirectory instead (#10097) gradle/gradle#20210 gradle/gradle#24820 --- app/build.gradle.kts | 4 ++-- build.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3d120e8aa..e3c2aa74f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -301,12 +301,12 @@ tasks { kotlinOptions.freeCompilerArgs += listOf( "-P", "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + - project.buildDir.absolutePath + "/compose_metrics", + project.layout.buildDirectory.dir("compose_metrics").get().asFile.absolutePath, ) kotlinOptions.freeCompilerArgs += listOf( "-P", "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + - project.buildDir.absolutePath + "/compose_metrics", + project.layout.buildDirectory.dir("compose_metrics").get().asFile.absolutePath, ) } } diff --git a/build.gradle.kts b/build.gradle.kts index 1e5493377..2de38cbab 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -56,5 +56,5 @@ subprojects { } tasks.register("clean") { - delete(rootProject.buildDir) + delete(rootProject.layout.buildDirectory) } From d862d83511d6bc7dee53609bcac77c20b01bc795 Mon Sep 17 00:00:00 2001 From: Eshlender <35057681+e-shl@users.noreply.github.com> Date: Wed, 1 Nov 2023 18:01:38 +0500 Subject: [PATCH 33/66] Combining manga information into a function (#10093) * Combining manga information into a function * clean space * indexes * context * clean * textAlign for Tablet Mode --- .../manga/components/MangaInfoHeader.kt | 360 +++++++----------- 1 file changed, 148 insertions(+), 212 deletions(-) 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 a88aa7a7e..570812442 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 @@ -1,6 +1,5 @@ package eu.kanade.presentation.manga.components -import android.content.Context import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.graphics.res.animatedVectorResource @@ -43,6 +42,7 @@ import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalMinimumInteractiveComponentEnforcement +import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ProvideTextStyle import androidx.compose.material3.SuggestionChip @@ -134,7 +134,6 @@ fun MangaInfoBox( coverDataProvider = coverDataProvider, onCoverClick = onCoverClick, title = title, - context = LocalContext.current, doSearch = doSearch, author = author, artist = artist, @@ -148,7 +147,6 @@ fun MangaInfoBox( coverDataProvider = coverDataProvider, onCoverClick = onCoverClick, title = title, - context = LocalContext.current, doSearch = doSearch, author = author, artist = artist, @@ -323,7 +321,6 @@ private fun MangaAndSourceTitlesLarge( coverDataProvider: () -> Manga, onCoverClick: () -> Unit, title: String, - context: Context, doSearch: (query: String, global: Boolean) -> Unit, author: String?, artist: String?, @@ -344,102 +341,16 @@ private fun MangaAndSourceTitlesLarge( onClick = onCoverClick, ) Spacer(modifier = Modifier.height(16.dp)) - Text( - text = title.ifBlank { stringResource(R.string.unknown_title) }, - style = MaterialTheme.typography.titleLarge, - modifier = Modifier.clickableNoIndication( - onLongClick = { if (title.isNotBlank()) context.copyToClipboard(title, title) }, - onClick = { if (title.isNotBlank()) doSearch(title, true) }, - ), + MangaContentInfo( + title = title, + doSearch = doSearch, + author = author, + artist = artist, + status = status, + sourceName = sourceName, + isStubSource = isStubSource, textAlign = TextAlign.Center, ) - Spacer(modifier = Modifier.height(2.dp)) - Text( - text = author?.takeIf { it.isNotBlank() } ?: stringResource(R.string.unknown_author), - style = MaterialTheme.typography.titleSmall, - modifier = Modifier - .secondaryItemAlpha() - .padding(top = 2.dp) - .clickableNoIndication( - onLongClick = { - if (!author.isNullOrBlank()) { - context.copyToClipboard( - author, - author, - ) - } - }, - onClick = { if (!author.isNullOrBlank()) doSearch(author, true) }, - ), - textAlign = TextAlign.Center, - ) - if (!artist.isNullOrBlank() && author != artist) { - Text( - text = artist, - style = MaterialTheme.typography.titleSmall, - modifier = Modifier - .secondaryItemAlpha() - .padding(top = 2.dp) - .clickableNoIndication( - onLongClick = { context.copyToClipboard(artist, artist) }, - onClick = { doSearch(artist, true) }, - ), - textAlign = TextAlign.Center, - ) - } - Spacer(modifier = Modifier.height(4.dp)) - Row( - modifier = Modifier.secondaryItemAlpha(), - verticalAlignment = Alignment.CenterVertically, - ) { - Icon( - imageVector = when (status) { - SManga.ONGOING.toLong() -> Icons.Outlined.Schedule - SManga.COMPLETED.toLong() -> Icons.Outlined.DoneAll - SManga.LICENSED.toLong() -> Icons.Outlined.AttachMoney - SManga.PUBLISHING_FINISHED.toLong() -> Icons.Outlined.Done - SManga.CANCELLED.toLong() -> Icons.Outlined.Close - SManga.ON_HIATUS.toLong() -> Icons.Outlined.Pause - else -> Icons.Outlined.Block - }, - contentDescription = null, - modifier = Modifier - .padding(end = 4.dp) - .size(16.dp), - ) - ProvideTextStyle(MaterialTheme.typography.bodyMedium) { - Text( - text = when (status) { - SManga.ONGOING.toLong() -> stringResource(R.string.ongoing) - SManga.COMPLETED.toLong() -> stringResource(R.string.completed) - SManga.LICENSED.toLong() -> stringResource(R.string.licensed) - SManga.PUBLISHING_FINISHED.toLong() -> stringResource(R.string.publishing_finished) - SManga.CANCELLED.toLong() -> stringResource(R.string.cancelled) - SManga.ON_HIATUS.toLong() -> stringResource(R.string.on_hiatus) - else -> stringResource(R.string.unknown) - }, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - ) - DotSeparatorText() - if (isStubSource) { - Icon( - imageVector = Icons.Filled.Warning, - contentDescription = null, - modifier = Modifier - .padding(end = 4.dp) - .size(16.dp), - tint = MaterialTheme.colorScheme.error, - ) - } - Text( - text = sourceName, - modifier = Modifier.clickableNoIndication { doSearch(sourceName, false) }, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - ) - } - } } } @@ -449,7 +360,6 @@ private fun MangaAndSourceTitlesSmall( coverDataProvider: () -> Manga, onCoverClick: () -> Unit, title: String, - context: Context, doSearch: (query: String, global: Boolean) -> Unit, author: String?, artist: String?, @@ -475,135 +385,161 @@ private fun MangaAndSourceTitlesSmall( Column( verticalArrangement = Arrangement.spacedBy(2.dp), ) { - Text( - text = title.ifBlank { stringResource(R.string.unknown_title) }, - style = MaterialTheme.typography.titleLarge, - modifier = Modifier.clickableNoIndication( + MangaContentInfo( + title = title, + doSearch = doSearch, + author = author, + artist = artist, + status = status, + sourceName = sourceName, + isStubSource = isStubSource, + ) + } + } +} + +@Composable +private fun MangaContentInfo( + title: String, + textAlign: TextAlign? = LocalTextStyle.current.textAlign, + doSearch: (query: String, global: Boolean) -> Unit, + author: String?, + artist: String?, + status: Long, + sourceName: String, + isStubSource: Boolean, +) { + val context = LocalContext.current + Text( + text = title.ifBlank { stringResource(R.string.unknown_title) }, + style = MaterialTheme.typography.titleLarge, + modifier = Modifier.clickableNoIndication( + onLongClick = { + if (title.isNotBlank()) { + context.copyToClipboard( + title, + title, + ) + } + }, + onClick = { if (title.isNotBlank()) doSearch(title, true) }, + ), + textAlign = textAlign, + ) + + Spacer(modifier = Modifier.height(2.dp)) + + Row( + modifier = Modifier.secondaryItemAlpha(), + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = Icons.Filled.PersonOutline, + contentDescription = null, + modifier = Modifier.size(16.dp), + ) + Text( + text = author?.takeIf { it.isNotBlank() } + ?: stringResource(R.string.unknown_author), + style = MaterialTheme.typography.titleSmall, + modifier = Modifier + .clickableNoIndication( onLongClick = { - if (title.isNotBlank()) { + if (!author.isNullOrBlank()) { context.copyToClipboard( - title, - title, + author, + author, ) } }, - onClick = { if (title.isNotBlank()) doSearch(title, true) }, + onClick = { if (!author.isNullOrBlank()) doSearch(author, true) }, ), + textAlign = textAlign, + ) + } + + if (!artist.isNullOrBlank() && author != artist) { + Row( + modifier = Modifier.secondaryItemAlpha(), + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = Icons.Filled.Brush, + contentDescription = null, + modifier = Modifier.size(16.dp), ) + Text( + text = artist, + style = MaterialTheme.typography.titleSmall, + modifier = Modifier + .clickableNoIndication( + onLongClick = { context.copyToClipboard(artist, artist) }, + onClick = { doSearch(artist, true) }, + ), + textAlign = textAlign, + ) + } + } - Spacer(modifier = Modifier.height(2.dp)) + Spacer(modifier = Modifier.height(2.dp)) - Row( - modifier = Modifier.secondaryItemAlpha(), - horizontalArrangement = Arrangement.spacedBy(4.dp), - verticalAlignment = Alignment.CenterVertically, - ) { + Row( + modifier = Modifier.secondaryItemAlpha(), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = when (status) { + SManga.ONGOING.toLong() -> Icons.Outlined.Schedule + SManga.COMPLETED.toLong() -> Icons.Outlined.DoneAll + SManga.LICENSED.toLong() -> Icons.Outlined.AttachMoney + SManga.PUBLISHING_FINISHED.toLong() -> Icons.Outlined.Done + SManga.CANCELLED.toLong() -> Icons.Outlined.Close + SManga.ON_HIATUS.toLong() -> Icons.Outlined.Pause + else -> Icons.Outlined.Block + }, + contentDescription = null, + modifier = Modifier + .padding(end = 4.dp) + .size(16.dp), + ) + ProvideTextStyle(MaterialTheme.typography.bodyMedium) { + Text( + text = when (status) { + SManga.ONGOING.toLong() -> stringResource(R.string.ongoing) + SManga.COMPLETED.toLong() -> stringResource(R.string.completed) + SManga.LICENSED.toLong() -> stringResource(R.string.licensed) + SManga.PUBLISHING_FINISHED.toLong() -> stringResource(R.string.publishing_finished) + SManga.CANCELLED.toLong() -> stringResource(R.string.cancelled) + SManga.ON_HIATUS.toLong() -> stringResource(R.string.on_hiatus) + else -> stringResource(R.string.unknown) + }, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + ) + DotSeparatorText() + if (isStubSource) { Icon( - imageVector = Icons.Filled.PersonOutline, - contentDescription = null, - modifier = Modifier.size(16.dp), - ) - Text( - text = author?.takeIf { it.isNotBlank() } - ?: stringResource(R.string.unknown_author), - style = MaterialTheme.typography.titleSmall, - modifier = Modifier - .clickableNoIndication( - onLongClick = { - if (!author.isNullOrBlank()) { - context.copyToClipboard( - author, - author, - ) - } - }, - onClick = { if (!author.isNullOrBlank()) doSearch(author, true) }, - ), - ) - } - - if (!artist.isNullOrBlank() && author != artist) { - Row( - modifier = Modifier.secondaryItemAlpha(), - horizontalArrangement = Arrangement.spacedBy(4.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Icon( - imageVector = Icons.Filled.Brush, - contentDescription = null, - modifier = Modifier.size(16.dp), - ) - Text( - text = artist, - style = MaterialTheme.typography.titleSmall, - modifier = Modifier - .clickableNoIndication( - onLongClick = { context.copyToClipboard(artist, artist) }, - onClick = { doSearch(artist, true) }, - ), - ) - } - } - - Spacer(modifier = Modifier.height(2.dp)) - - Row( - modifier = Modifier.secondaryItemAlpha(), - verticalAlignment = Alignment.CenterVertically, - ) { - Icon( - imageVector = when (status) { - SManga.ONGOING.toLong() -> Icons.Outlined.Schedule - SManga.COMPLETED.toLong() -> Icons.Outlined.DoneAll - SManga.LICENSED.toLong() -> Icons.Outlined.AttachMoney - SManga.PUBLISHING_FINISHED.toLong() -> Icons.Outlined.Done - SManga.CANCELLED.toLong() -> Icons.Outlined.Close - SManga.ON_HIATUS.toLong() -> Icons.Outlined.Pause - else -> Icons.Outlined.Block - }, + imageVector = Icons.Filled.Warning, contentDescription = null, modifier = Modifier .padding(end = 4.dp) .size(16.dp), + tint = MaterialTheme.colorScheme.error, ) - ProvideTextStyle(MaterialTheme.typography.bodyMedium) { - Text( - text = when (status) { - SManga.ONGOING.toLong() -> stringResource(R.string.ongoing) - SManga.COMPLETED.toLong() -> stringResource(R.string.completed) - SManga.LICENSED.toLong() -> stringResource(R.string.licensed) - SManga.PUBLISHING_FINISHED.toLong() -> stringResource(R.string.publishing_finished) - SManga.CANCELLED.toLong() -> stringResource(R.string.cancelled) - SManga.ON_HIATUS.toLong() -> stringResource(R.string.on_hiatus) - else -> stringResource(R.string.unknown) - }, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - ) - DotSeparatorText() - if (isStubSource) { - Icon( - imageVector = Icons.Filled.Warning, - contentDescription = null, - modifier = Modifier - .padding(end = 4.dp) - .size(16.dp), - tint = MaterialTheme.colorScheme.error, - ) - } - Text( - text = sourceName, - modifier = Modifier.clickableNoIndication { - doSearch( - sourceName, - false, - ) - }, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - ) - } } + Text( + text = sourceName, + modifier = Modifier.clickableNoIndication { + doSearch( + sourceName, + false, + ) + }, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + ) } } } From b3d7c9247530c0522033b4a9130d252bcbf50163 Mon Sep 17 00:00:00 2001 From: Eshlender <35057681+e-shl@users.noreply.github.com> Date: Thu, 2 Nov 2023 07:17:17 +0500 Subject: [PATCH 34/66] Text on tabs Overflow Ellipsis (#10095) * Update TabbedDialog to TabbedScreen * clean --- .../presentation/components/TabbedDialog.kt | 21 ++++++------------- .../core/components/material/Tabs.kt | 7 ++++++- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt b/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt index 675f35360..20e3640c9 100644 --- a/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/components/TabbedDialog.kt @@ -16,7 +16,6 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Tab import androidx.compose.material3.TabRow -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -32,6 +31,7 @@ import eu.kanade.tachiyomi.R import kotlinx.coroutines.launch import tachiyomi.presentation.core.components.HorizontalPager import tachiyomi.presentation.core.components.material.TabIndicator +import tachiyomi.presentation.core.components.material.TabText object TabbedDialogPaddings { val Horizontal = 24.dp @@ -61,21 +61,12 @@ fun TabbedDialog( indicator = { TabIndicator(it[pagerState.currentPage], pagerState.currentPageOffsetFraction) }, divider = {}, ) { - tabTitles.fastForEachIndexed { i, tab -> - val selected = pagerState.currentPage == i + tabTitles.fastForEachIndexed { index, tab -> Tab( - selected = selected, - onClick = { scope.launch { pagerState.animateScrollToPage(i) } }, - text = { - Text( - text = tab, - color = if (selected) { - MaterialTheme.colorScheme.primary - } else { - MaterialTheme.colorScheme.onSurfaceVariant - }, - ) - }, + selected = pagerState.currentPage == index, + onClick = { scope.launch { pagerState.animateScrollToPage(index) } }, + text = { TabText(text = tab) }, + unselectedContentColor = MaterialTheme.colorScheme.onSurface, ) } } 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 66e44ca24..0770d577a 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 @@ -21,6 +21,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.composed import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -62,7 +63,11 @@ fun TabText(text: String, badgeCount: Int? = null) { Row( verticalAlignment = Alignment.CenterVertically, ) { - Text(text = text) + Text( + text = text, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) if (badgeCount != null) { Pill( text = "$badgeCount", From 6d538db5f2afc45976a65ae5d202a490d2e08352 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Thu, 2 Nov 2023 08:18:19 +0600 Subject: [PATCH 35/66] Show missing chapter count between two chapters in chapter list (#10096) * Show missing chapter count between two chapters in chapter list Closes #8460 * Fix crash * Lint * Review changes * Lint --- .../domain/chapter/model/ChapterFilter.kt | 4 +- .../kanade/presentation/manga/MangaScreen.kt | 196 +++++++++++------- .../tachiyomi/ui/manga/MangaScreenModel.kt | 92 +++++--- .../util/chapter/ChapterGetNextUnread.kt | 4 +- 4 files changed, 189 insertions(+), 107 deletions(-) diff --git a/app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt b/app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt index 623ddd751..6ddf2f33f 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt @@ -2,7 +2,7 @@ package eu.kanade.domain.chapter.model import eu.kanade.domain.manga.model.downloadedFilter import eu.kanade.tachiyomi.data.download.DownloadManager -import eu.kanade.tachiyomi.ui.manga.ChapterItem +import eu.kanade.tachiyomi.ui.manga.ChapterList import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.service.getChapterSort import tachiyomi.domain.manga.model.Manga @@ -34,7 +34,7 @@ fun List.applyFilters(manga: Manga, downloadManager: DownloadManager): * Applies the view filters to the list of chapters obtained from the database. * @return an observable of the list of chapters filtered and sorted. */ -fun List.applyFilters(manga: Manga): Sequence { +fun List.applyFilters(manga: Manga): Sequence { val isLocalManga = manga.isLocal() val unreadFilter = manga.unreadFilter val downloadedFilter = manga.downloadedFilter 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 82c266f65..83b35bd46 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -5,9 +5,11 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.asPaddingValues @@ -26,7 +28,9 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text @@ -44,6 +48,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.util.fastAll import androidx.compose.ui.util.fastAny @@ -61,7 +66,7 @@ import eu.kanade.presentation.util.formatChapterNumber import eu.kanade.tachiyomi.R 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.ChapterList import eu.kanade.tachiyomi.ui.manga.MangaScreenModel import eu.kanade.tachiyomi.util.lang.toRelativeString import eu.kanade.tachiyomi.util.system.copyToClipboard @@ -75,8 +80,10 @@ import tachiyomi.presentation.core.components.VerticalFastScroller import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton import tachiyomi.presentation.core.components.material.PullRefresh import tachiyomi.presentation.core.components.material.Scaffold +import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.util.isScrolledToEnd import tachiyomi.presentation.core.util.isScrollingUp +import tachiyomi.presentation.core.util.secondaryItemAlpha import java.text.DateFormat import java.util.Date @@ -92,7 +99,7 @@ fun MangaScreen( chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onBackClicked: () -> Unit, onChapterClicked: (Chapter) -> Unit, - onDownloadChapter: ((List, ChapterDownloadAction) -> Unit)?, + onDownloadChapter: ((List, ChapterDownloadAction) -> Unit)?, onAddToLibraryClicked: () -> Unit, onWebViewClicked: (() -> Unit)?, onWebViewLongClicked: (() -> Unit)?, @@ -123,10 +130,10 @@ fun MangaScreen( onMultiDeleteClicked: (List) -> Unit, // For chapter swipe - onChapterSwipe: (ChapterItem, LibraryPreferences.ChapterSwipeAction) -> Unit, + onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, // Chapter selection - onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit, + onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, onAllChapterSelected: (Boolean) -> Unit, onInvertSelection: () -> Unit, ) { @@ -225,7 +232,7 @@ private fun MangaScreenSmallImpl( chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onBackClicked: () -> Unit, onChapterClicked: (Chapter) -> Unit, - onDownloadChapter: ((List, ChapterDownloadAction) -> Unit)?, + onDownloadChapter: ((List, ChapterDownloadAction) -> Unit)?, onAddToLibraryClicked: () -> Unit, onWebViewClicked: (() -> Unit)?, onWebViewLongClicked: (() -> Unit)?, @@ -257,16 +264,17 @@ private fun MangaScreenSmallImpl( onMultiDeleteClicked: (List) -> Unit, // For chapter swipe - onChapterSwipe: (ChapterItem, LibraryPreferences.ChapterSwipeAction) -> Unit, + onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, // Chapter selection - onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit, + onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, onAllChapterSelected: (Boolean) -> Unit, onInvertSelection: () -> Unit, ) { val chapterListState = rememberLazyListState() val chapters = remember(state) { state.processedChapters } + val listItem = remember(state) { state.chapterListItems } val isAnySelected by remember { derivedStateOf { @@ -447,7 +455,8 @@ private fun MangaScreenSmallImpl( sharedChapterItems( manga = state.manga, - chapters = chapters, + chapters = listItem, + isAnyChapterSelected = chapters.fastAny { it.selected }, dateRelativeTime = dateRelativeTime, dateFormat = dateFormat, chapterSwipeStartAction = chapterSwipeStartAction, @@ -474,7 +483,7 @@ fun MangaScreenLargeImpl( chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onBackClicked: () -> Unit, onChapterClicked: (Chapter) -> Unit, - onDownloadChapter: ((List, ChapterDownloadAction) -> Unit)?, + onDownloadChapter: ((List, ChapterDownloadAction) -> Unit)?, onAddToLibraryClicked: () -> Unit, onWebViewClicked: (() -> Unit)?, onWebViewLongClicked: (() -> Unit)?, @@ -506,10 +515,10 @@ fun MangaScreenLargeImpl( onMultiDeleteClicked: (List) -> Unit, // For swipe actions - onChapterSwipe: (ChapterItem, LibraryPreferences.ChapterSwipeAction) -> Unit, + onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, // Chapter selection - onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit, + onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, onAllChapterSelected: (Boolean) -> Unit, onInvertSelection: () -> Unit, ) { @@ -517,6 +526,7 @@ fun MangaScreenLargeImpl( val density = LocalDensity.current val chapters = remember(state) { state.processedChapters } + val listItem = remember(state) { state.chapterListItems } val isAnySelected by remember { derivedStateOf { @@ -688,7 +698,8 @@ fun MangaScreenLargeImpl( sharedChapterItems( manga = state.manga, - chapters = chapters, + chapters = listItem, + isAnyChapterSelected = chapters.fastAny { it.selected }, dateRelativeTime = dateRelativeTime, dateFormat = dateFormat, chapterSwipeStartAction = chapterSwipeStartAction, @@ -708,12 +719,12 @@ fun MangaScreenLargeImpl( @Composable private fun SharedMangaBottomActionMenu( - selected: List, + selected: List, modifier: Modifier = Modifier, onMultiBookmarkClicked: (List, bookmarked: Boolean) -> Unit, onMultiMarkAsReadClicked: (List, markAsRead: Boolean) -> Unit, onMarkPreviousAsReadClicked: (Chapter) -> Unit, - onDownloadChapter: ((List, ChapterDownloadAction) -> Unit)?, + onDownloadChapter: ((List, ChapterDownloadAction) -> Unit)?, onMultiDeleteClicked: (List) -> Unit, fillFraction: Float, ) { @@ -750,92 +761,123 @@ private fun SharedMangaBottomActionMenu( private fun LazyListScope.sharedChapterItems( manga: Manga, - chapters: List, + chapters: List, + isAnyChapterSelected: Boolean, dateRelativeTime: Boolean, dateFormat: DateFormat, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onChapterClicked: (Chapter) -> Unit, - onDownloadChapter: ((List, ChapterDownloadAction) -> Unit)?, - onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit, - onChapterSwipe: (ChapterItem, LibraryPreferences.ChapterSwipeAction) -> Unit, + onDownloadChapter: ((List, ChapterDownloadAction) -> Unit)?, + onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit, + onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit, ) { items( items = chapters, - key = { "chapter-${it.chapter.id}" }, + key = { item -> + when (item) { + is ChapterList.MissingCount -> "missing-count-${item.id}" + is ChapterList.Item -> "chapter-${item.id}" + } + }, contentType = { MangaScreenItem.CHAPTER }, - ) { chapterItem -> + ) { item -> val haptic = LocalHapticFeedback.current val context = LocalContext.current - MangaChapterListItem( - title = if (manga.displayMode == Manga.CHAPTER_DISPLAY_NUMBER) { - stringResource( - R.string.display_mode_chapter, - formatChapterNumber(chapterItem.chapter.chapterNumber), - ) - } else { - chapterItem.chapter.name - }, - date = chapterItem.chapter.dateUpload - .takeIf { it > 0L } - ?.let { - Date(it).toRelativeString( - context, - dateRelativeTime, - dateFormat, + when (item) { + is ChapterList.MissingCount -> { + Row( + modifier = Modifier.padding( + horizontal = MaterialTheme.padding.medium, + vertical = MaterialTheme.padding.small, + ), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.medium), + ) { + HorizontalDivider(modifier = Modifier.weight(1f)) + Text( + text = pluralStringResource( + id = R.plurals.missing_chapters, + count = item.count, + item.count, + ), + modifier = Modifier.secondaryItemAlpha(), ) - }, - readProgress = chapterItem.chapter.lastPageRead - .takeIf { !chapterItem.chapter.read && it > 0L } - ?.let { - stringResource( - R.string.chapter_progress, - it + 1, - ) - }, - scanlator = chapterItem.chapter.scanlator.takeIf { !it.isNullOrBlank() }, - read = chapterItem.chapter.read, - bookmark = chapterItem.chapter.bookmark, - selected = chapterItem.selected, - downloadIndicatorEnabled = chapters.fastAll { !it.selected }, - downloadStateProvider = { chapterItem.downloadState }, - downloadProgressProvider = { chapterItem.downloadProgress }, - chapterSwipeStartAction = chapterSwipeStartAction, - chapterSwipeEndAction = chapterSwipeEndAction, - onLongClick = { - onChapterSelected(chapterItem, !chapterItem.selected, true, true) - haptic.performHapticFeedback(HapticFeedbackType.LongPress) - }, - onClick = { - onChapterItemClick( - chapterItem = chapterItem, - chapters = chapters, - onToggleSelection = { onChapterSelected(chapterItem, !chapterItem.selected, true, false) }, - onChapterClicked = onChapterClicked, + HorizontalDivider(modifier = Modifier.weight(1f)) + } + } + is ChapterList.Item -> { + MangaChapterListItem( + title = if (manga.displayMode == Manga.CHAPTER_DISPLAY_NUMBER) { + stringResource( + R.string.display_mode_chapter, + formatChapterNumber(item.chapter.chapterNumber), + ) + } else { + item.chapter.name + }, + date = item.chapter.dateUpload + .takeIf { it > 0L } + ?.let { + Date(it).toRelativeString( + context, + dateRelativeTime, + dateFormat, + ) + }, + readProgress = item.chapter.lastPageRead + .takeIf { !item.chapter.read && it > 0L } + ?.let { + stringResource( + R.string.chapter_progress, + it + 1, + ) + }, + scanlator = item.chapter.scanlator.takeIf { !it.isNullOrBlank() }, + read = item.chapter.read, + bookmark = item.chapter.bookmark, + selected = item.selected, + downloadIndicatorEnabled = !isAnyChapterSelected, + downloadStateProvider = { item.downloadState }, + downloadProgressProvider = { item.downloadProgress }, + chapterSwipeStartAction = chapterSwipeStartAction, + chapterSwipeEndAction = chapterSwipeEndAction, + onLongClick = { + onChapterSelected(item, !item.selected, true, true) + haptic.performHapticFeedback(HapticFeedbackType.LongPress) + }, + onClick = { + onChapterItemClick( + chapterItem = item, + isAnyChapterSelected = isAnyChapterSelected, + onToggleSelection = { onChapterSelected(item, !item.selected, true, false) }, + onChapterClicked = onChapterClicked, + ) + }, + onDownloadClick = if (onDownloadChapter != null) { + { onDownloadChapter(listOf(item), it) } + } else { + null + }, + onChapterSwipe = { + onChapterSwipe(item, it) + }, ) - }, - onDownloadClick = if (onDownloadChapter != null) { - { onDownloadChapter(listOf(chapterItem), it) } - } else { - null - }, - onChapterSwipe = { - onChapterSwipe(chapterItem, it) - }, - ) + } + } } } private fun onChapterItemClick( - chapterItem: ChapterItem, - chapters: List, + chapterItem: ChapterList.Item, + isAnyChapterSelected: Boolean, onToggleSelection: (Boolean) -> Unit, onChapterClicked: (Chapter) -> Unit, ) { when { chapterItem.selected -> onToggleSelection(false) - chapters.fastAny { it.selected } -> onToggleSelection(true) + isAnyChapterSelected -> onToggleSelection(true) else -> onChapterClicked(chapterItem.chapter) } } 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 a4f6f5d95..4fa4baba5 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 @@ -10,6 +10,7 @@ import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.core.preference.asState import eu.kanade.core.util.addOrRemove +import eu.kanade.core.util.insertSeparators import eu.kanade.domain.chapter.interactor.SetReadStatus import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.manga.interactor.UpdateManga @@ -61,6 +62,7 @@ import tachiyomi.domain.chapter.interactor.UpdateChapter import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.model.ChapterUpdate import tachiyomi.domain.chapter.model.NoChaptersException +import tachiyomi.domain.chapter.service.calculateChapterGap import tachiyomi.domain.chapter.service.getChapterSort import tachiyomi.domain.download.service.DownloadPreferences import tachiyomi.domain.library.service.LibraryPreferences @@ -75,6 +77,7 @@ import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.source.local.isLocal import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import kotlin.math.floor class MangaScreenModel( val context: Context, @@ -117,10 +120,10 @@ class MangaScreenModel( private val isFavorited: Boolean get() = manga?.favorite ?: false - private val allChapters: List? + private val allChapters: List? get() = successState?.chapters - private val filteredChapters: List? + private val filteredChapters: List? get() = successState?.processedChapters val chapterSwipeStartAction = libraryPreferences.swipeToEndAction().get() @@ -158,7 +161,7 @@ class MangaScreenModel( updateSuccessState { it.copy( manga = manga, - chapters = chapters.toChapterItems(manga), + chapters = chapters.toChapterListItems(manga), ) } } @@ -169,7 +172,7 @@ class MangaScreenModel( screenModelScope.launchIO { val manga = getMangaAndChapters.awaitManga(mangaId) val chapters = getMangaAndChapters.awaitChapters(mangaId) - .toChapterItems(manga) + .toChapterListItems(manga) if (!manga.favorite) { setMangaDefaultChapterFlags.await(manga) @@ -455,7 +458,7 @@ class MangaScreenModel( private fun updateDownloadState(download: Download) { updateSuccessState { successState -> - val modifiedIndex = successState.chapters.indexOfFirst { it.chapter.id == download.chapter.id } + val modifiedIndex = successState.chapters.indexOfFirst { it.id == download.chapter.id } if (modifiedIndex < 0) return@updateSuccessState successState val newChapters = successState.chapters.toMutableList().apply { @@ -467,7 +470,7 @@ class MangaScreenModel( } } - private fun List.toChapterItems(manga: Manga): List { + private fun List.toChapterListItems(manga: Manga): List { val isLocal = manga.isLocal() return map { chapter -> val activeDownload = if (isLocal) { @@ -486,7 +489,7 @@ class MangaScreenModel( else -> Download.State.NOT_DOWNLOADED } - ChapterItem( + ChapterList.Item( chapter = chapter, downloadState = downloadState, downloadProgress = activeDownload?.progress ?: 0, @@ -534,7 +537,7 @@ class MangaScreenModel( /** * @throws IllegalStateException if the swipe action is [LibraryPreferences.ChapterSwipeAction.Disabled] */ - fun chapterSwipe(chapterItem: ChapterItem, swipeAction: LibraryPreferences.ChapterSwipeAction) { + fun chapterSwipe(chapterItem: ChapterList.Item, swipeAction: LibraryPreferences.ChapterSwipeAction) { screenModelScope.launch { executeChapterSwipeAction(chapterItem, swipeAction) } @@ -544,7 +547,7 @@ class MangaScreenModel( * @throws IllegalStateException if the swipe action is [LibraryPreferences.ChapterSwipeAction.Disabled] */ private fun executeChapterSwipeAction( - chapterItem: ChapterItem, + chapterItem: ChapterList.Item, swipeAction: LibraryPreferences.ChapterSwipeAction, ) { val chapter = chapterItem.chapter @@ -626,7 +629,7 @@ class MangaScreenModel( } fun runChapterDownloadActions( - items: List, + items: List, action: ChapterDownloadAction, ) { when (action) { @@ -641,7 +644,7 @@ class MangaScreenModel( startDownload(listOf(chapter), true) } ChapterDownloadAction.CANCEL -> { - val chapterId = items.singleOrNull()?.chapter?.id ?: return + val chapterId = items.singleOrNull()?.id ?: return cancelDownload(chapterId) } ChapterDownloadAction.DELETE -> { @@ -842,14 +845,14 @@ class MangaScreenModel( } fun toggleSelection( - item: ChapterItem, + item: ChapterList.Item, selected: Boolean, userSelected: Boolean = false, fromLongPress: Boolean = false, ) { updateSuccessState { successState -> val newChapters = successState.processedChapters.toMutableList().apply { - val selectedIndex = successState.processedChapters.indexOfFirst { it.chapter.id == item.chapter.id } + val selectedIndex = successState.processedChapters.indexOfFirst { it.id == item.chapter.id } if (selectedIndex < 0) return@apply val selectedItem = get(selectedIndex) @@ -857,7 +860,7 @@ class MangaScreenModel( val firstSelection = none { it.selected } set(selectedIndex, selectedItem.copy(selected = selected)) - selectedChapterIds.addOrRemove(item.chapter.id, selected) + selectedChapterIds.addOrRemove(item.id, selected) if (selected && userSelected && fromLongPress) { if (firstSelection) { @@ -880,7 +883,7 @@ class MangaScreenModel( range.forEach { val inbetweenItem = get(it) if (!inbetweenItem.selected) { - selectedChapterIds.add(inbetweenItem.chapter.id) + selectedChapterIds.add(inbetweenItem.id) set(it, inbetweenItem.copy(selected = true)) } } @@ -908,7 +911,7 @@ class MangaScreenModel( fun toggleAllSelection(selected: Boolean) { updateSuccessState { successState -> val newChapters = successState.chapters.map { - selectedChapterIds.addOrRemove(it.chapter.id, selected) + selectedChapterIds.addOrRemove(it.id, selected) it.copy(selected = selected) } selectedPositions[0] = -1 @@ -920,7 +923,7 @@ class MangaScreenModel( fun invertSelection() { updateSuccessState { successState -> val newChapters = successState.chapters.map { - selectedChapterIds.addOrRemove(it.chapter.id, !it.selected) + selectedChapterIds.addOrRemove(it.id, !it.selected) it.copy(selected = !it.selected) } selectedPositions[0] = -1 @@ -994,7 +997,7 @@ class MangaScreenModel( val manga: Manga, val source: Source, val isFromSource: Boolean, - val chapters: List, + val chapters: List, val trackItems: List = emptyList(), val isRefreshingData: Boolean = false, val dialog: Dialog? = null, @@ -1005,6 +1008,33 @@ class MangaScreenModel( chapters.applyFilters(manga).toList() } + val chapterListItems by lazy { + processedChapters.insertSeparators { before, after -> + val (lowerChapter, higherChapter) = if (manga.sortDescending()) { + after to before + } else { + before to after + } + if (higherChapter == null) return@insertSeparators null + + if (lowerChapter == null) { + floor(higherChapter.chapter.chapterNumber) + .toInt() + .minus(1) + .coerceAtLeast(0) + } else { + calculateChapterGap(higherChapter.chapter, lowerChapter.chapter) + } + .takeIf { it > 0 } + ?.let { missingCount -> + ChapterList.MissingCount( + id = "${lowerChapter?.id}-${higherChapter.id}", + count = missingCount, + ) + } + } + } + val trackingAvailable: Boolean get() = trackItems.isNotEmpty() @@ -1015,7 +1045,7 @@ class MangaScreenModel( * Applies the view filters to the list of chapters obtained from the database. * @return an observable of the list of chapters filtered and sorted. */ - private fun List.applyFilters(manga: Manga): Sequence { + private fun List.applyFilters(manga: Manga): Sequence { val isLocalManga = manga.isLocal() val unreadFilter = manga.unreadFilter val downloadedFilter = manga.downloadedFilter @@ -1031,11 +1061,21 @@ class MangaScreenModel( } @Immutable -data class ChapterItem( - val chapter: Chapter, - val downloadState: Download.State, - val downloadProgress: Int, - val selected: Boolean = false, -) { - val isDownloaded = downloadState == Download.State.DOWNLOADED +sealed class ChapterList { + @Immutable + data class MissingCount( + val id: String, + val count: Int, + ) : ChapterList() + + @Immutable + data class Item( + val chapter: Chapter, + val downloadState: Download.State, + val downloadProgress: Int, + val selected: Boolean = false, + ) : ChapterList() { + val id = chapter.id + val isDownloaded = downloadState == Download.State.DOWNLOADED + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterGetNextUnread.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterGetNextUnread.kt index 418220a46..a7accb08e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterGetNextUnread.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterGetNextUnread.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.util.chapter import eu.kanade.domain.chapter.model.applyFilters import eu.kanade.tachiyomi.data.download.DownloadManager -import eu.kanade.tachiyomi.ui.manga.ChapterItem +import eu.kanade.tachiyomi.ui.manga.ChapterList import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.model.Manga @@ -22,7 +22,7 @@ fun List.getNextUnread(manga: Manga, downloadManager: DownloadManager): /** * Gets next unread chapter with filters and sorting applied */ -fun List.getNextUnread(manga: Manga): Chapter? { +fun List.getNextUnread(manga: Manga): Chapter? { return applyFilters(manga).let { chapters -> if (manga.sortDescending()) { chapters.findLast { !it.chapter.read } From d5e8c38075aeb062d82b72c915c6c484386f91ed Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 1 Nov 2023 22:19:59 -0400 Subject: [PATCH 36/66] 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 98be1aa68..c3df15095 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -29,7 +29,7 @@ paging-compose = { module = "androidx.paging:paging-compose", version.ref = "pag benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0" 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" +test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0-alpha05" [bundles] lifecycle = ["lifecycle-common", "lifecycle-process", "lifecycle-runtimektx"] diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dfe6874e8..8753f7a07 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -65,7 +65,7 @@ swipe = "me.saket.swipe:swipe:1.2.0" logcat = "com.squareup.logcat:logcat:0.1" acra-http = "ch.acra:acra-http:5.11.3" -firebase-analytics = "com.google.firebase:firebase-analytics-ktx:21.4.0" +firebase-analytics = "com.google.firebase:firebase-analytics-ktx:21.5.0" aboutLibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin", version.ref = "aboutlib_version" } aboutLibraries-compose = { module = "com.mikepenz:aboutlibraries-compose", version.ref = "aboutlib_version" } From aca36f962516f04bbbac67c9bf54723a13076c1c Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 1 Nov 2023 22:52:00 -0400 Subject: [PATCH 37/66] Maybe fix foreign key error during some backup restores --- .../java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 753c3ef8e..726f20cd3 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 @@ -298,7 +298,6 @@ class BackupRestorer( .copyFrom(dbChapter) .copy( id = dbChapter.id, - mangaId = manga.id, bookmark = updatedChapter.bookmark || dbChapter.bookmark, ) if (dbChapter.read && !updatedChapter.read) { @@ -313,7 +312,7 @@ class BackupRestorer( } } - updatedChapter + updatedChapter.copy(mangaId = manga.id) } val (existingChapters, newChapters) = processed.partition { it.id > 0 } From 5d91b77c9340604436c63073c83ad8b37794ddf0 Mon Sep 17 00:00:00 2001 From: Caleb Morris Date: Sat, 4 Nov 2023 12:31:59 -0700 Subject: [PATCH 38/66] Added library sort by mean Tracker score (#10005) --- .../library/LibrarySettingsDialog.kt | 9 ++++- .../tachiyomi/data/track/TrackerManager.kt | 2 ++ .../ui/library/LibraryScreenModel.kt | 35 ++++++++++++++++--- .../domain/library/model/LibrarySortMode.kt | 4 +++ .../track/interactor/GetTracksPerManga.kt | 11 ++---- .../domain/library/model/LibraryFlagsTest.kt | 2 +- i18n/src/main/res/values/strings.xml | 1 + 7 files changed, 49 insertions(+), 15 deletions(-) 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 6d7882f43..c97740940 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -144,6 +144,13 @@ private fun ColumnScope.SortPage( val sortingMode = category.sort.type val sortDescending = !category.sort.isAscending + val trackerSortOption = + if (screenModel.trackers.isEmpty()) { + emptyList() + } else { + listOf(R.string.action_sort_tracker_score to LibrarySort.Type.TrackerMean) + } + listOf( R.string.action_sort_alpha to LibrarySort.Type.Alphabetical, R.string.action_sort_total to LibrarySort.Type.TotalChapters, @@ -153,7 +160,7 @@ private fun ColumnScope.SortPage( R.string.action_sort_latest_chapter to LibrarySort.Type.LatestChapter, R.string.action_sort_chapter_fetch_date to LibrarySort.Type.ChapterFetchDate, R.string.action_sort_date_added to LibrarySort.Type.DateAdded, - ).map { (titleRes, mode) -> + ).plus(trackerSortOption).map { (titleRes, mode) -> SortItem( label = stringResource(titleRes), sortDescending = sortDescending.takeIf { sortingMode == mode }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt index 3943537e2..a62ad4401 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt @@ -30,6 +30,8 @@ class TrackerManager { val trackers = listOf(myAnimeList, aniList, kitsu, shikimori, bangumi, komga, mangaUpdates, kavita, suwayomi) + fun loggedInTrackers() = trackers.filter { it.isLoggedIn } + fun get(id: Long) = trackers.find { it.id == id } fun hasLoggedIn() = trackers.any { it.isLoggedIn } 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 af0f5c81a..0120abcfc 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 @@ -61,6 +61,7 @@ import tachiyomi.domain.manga.model.MangaUpdate import tachiyomi.domain.manga.model.applyFilter import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.track.interactor.GetTracksPerManga +import tachiyomi.domain.track.model.Track import tachiyomi.source.local.isLocal import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -104,7 +105,7 @@ class LibraryScreenModel( ) { searchQuery, library, tracks, loggedInTrackers, _ -> library .applyFilters(tracks, loggedInTrackers) - .applySort() + .applySort(tracks) .mapValues { (_, value) -> if (searchQuery != null) { // Filter query @@ -168,7 +169,7 @@ class LibraryScreenModel( * Applies library filters to the given map of manga. */ private suspend fun LibraryMap.applyFilters( - trackMap: Map>, + trackMap: Map>, loggedInTrackers: Map, ): LibraryMap { val prefs = getLibraryItemPreferencesFlow().first() @@ -213,7 +214,9 @@ class LibraryScreenModel( val filterFnTracking: (LibraryItem) -> Boolean = tracking@{ item -> if (isNotLoggedInAnyTrack || trackFiltersIsIgnored) return@tracking true - val mangaTracks = trackMap[item.libraryManga.id].orEmpty() + val mangaTracks = trackMap + .mapValues { entry -> entry.value.map { it.syncId } }[item.libraryManga.id] + .orEmpty() val isExcluded = excludedTracks.isNotEmpty() && mangaTracks.fastAny { it in excludedTracks } val isIncluded = includedTracks.isEmpty() || mangaTracks.fastAny { it in includedTracks } @@ -236,7 +239,10 @@ class LibraryScreenModel( /** * Applies library sorting to the given map of manga. */ - private fun LibraryMap.applySort(): LibraryMap { + private fun LibraryMap.applySort( + // Map> + trackMap: Map>, + ): LibraryMap { val locale = Locale.getDefault() val collator = Collator.getInstance(locale).apply { strength = Collator.PRIMARY @@ -245,6 +251,20 @@ class LibraryScreenModel( collator.compare(i1.libraryManga.manga.title.lowercase(locale), i2.libraryManga.manga.title.lowercase(locale)) } + val defaultTrackerScoreSortValue = -1.0 + val trackerScores by lazy { + val trackerMap = trackerManager.loggedInTrackers().associateBy { e -> e.id } + trackMap.mapValues { entry -> + when { + entry.value.isEmpty() -> null + else -> + entry.value + .mapNotNull { trackerMap[it.syncId]?.get10PointScore(it) } + .average() + } + } + } + val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 -> val sort = keys.find { it.id == i1.libraryManga.category }!!.sort when (sort.type) { @@ -276,6 +296,11 @@ class LibraryScreenModel( LibrarySort.Type.DateAdded -> { i1.libraryManga.manga.dateAdded.compareTo(i2.libraryManga.manga.dateAdded) } + LibrarySort.Type.TrackerMean -> { + val item1Score = trackerScores[i1.libraryManga.id] ?: defaultTrackerScoreSortValue + val item2Score = trackerScores[i2.libraryManga.id] ?: defaultTrackerScoreSortValue + item1Score.compareTo(item2Score) + } } } @@ -366,7 +391,7 @@ class LibraryScreenModel( * @return map of track id with the filter value */ private fun getTrackingFilterFlow(): Flow> { - val loggedInTrackers = trackerManager.trackers.filter { it.isLoggedIn } + val loggedInTrackers = trackerManager.loggedInTrackers() return if (loggedInTrackers.isNotEmpty()) { val prefFlows = loggedInTrackers .map { libraryPreferences.filterTracking(it.id.toInt()).changes() } 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 7f525eb57..6a89d4e52 100644 --- a/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt +++ b/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt @@ -30,6 +30,7 @@ data class LibrarySort( data object LatestChapter : Type(0b00010100) data object ChapterFetchDate : Type(0b00011000) data object DateAdded : Type(0b00011100) + data object TrackerMean : Type(0b000100000) companion object { fun valueOf(flag: Long): Type { @@ -75,6 +76,7 @@ data class LibrarySort( Type.LatestChapter, Type.ChapterFetchDate, Type.DateAdded, + Type.TrackerMean, ) } val directions by lazy { setOf(Direction.Ascending, Direction.Descending) } @@ -101,6 +103,7 @@ data class LibrarySort( "LATEST_CHAPTER" -> Type.LatestChapter "CHAPTER_FETCH_DATE" -> Type.ChapterFetchDate "DATE_ADDED" -> Type.DateAdded + "TRACKER_MEAN" -> Type.TrackerMean else -> Type.Alphabetical } val ascending = if (values[1] == "ASCENDING") Direction.Ascending else Direction.Descending @@ -121,6 +124,7 @@ data class LibrarySort( Type.LatestChapter -> "LATEST_CHAPTER" Type.ChapterFetchDate -> "CHAPTER_FETCH_DATE" Type.DateAdded -> "DATE_ADDED" + Type.TrackerMean -> "TRACKER_MEAN" } val direction = if (direction == Direction.Ascending) "ASCENDING" else "DESCENDING" return "$type,$direction" diff --git a/domain/src/main/java/tachiyomi/domain/track/interactor/GetTracksPerManga.kt b/domain/src/main/java/tachiyomi/domain/track/interactor/GetTracksPerManga.kt index 9b8290d70..36478fdfe 100644 --- a/domain/src/main/java/tachiyomi/domain/track/interactor/GetTracksPerManga.kt +++ b/domain/src/main/java/tachiyomi/domain/track/interactor/GetTracksPerManga.kt @@ -2,19 +2,14 @@ package tachiyomi.domain.track.interactor import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map +import tachiyomi.domain.track.model.Track import tachiyomi.domain.track.repository.TrackRepository class GetTracksPerManga( private val trackRepository: TrackRepository, ) { - fun subscribe(): Flow>> { - return trackRepository.getTracksAsFlow().map { tracks -> - tracks - .groupBy { it.mangaId } - .mapValues { entry -> - entry.value.map { it.syncId } - } - } + fun subscribe(): Flow>> { + return trackRepository.getTracksAsFlow().map { tracks -> tracks.groupBy { it.mangaId } } } } 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 408dee18a..a3a223782 100644 --- a/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt +++ b/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt @@ -12,7 +12,7 @@ class LibraryFlagsTest { @Test fun `Check the amount of flags`() { LibraryDisplayMode.values.size shouldBe 4 - LibrarySort.types.size shouldBe 8 + LibrarySort.types.size shouldBe 9 LibrarySort.directions.size shouldBe 2 } diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 11df5d701..ef8354abc 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -66,6 +66,7 @@ Latest chapter Chapter fetch date Date added + Tracker score Search Search… Search settings From f30ab56fd0a2a748f84dd698874cb16d7a61bd62 Mon Sep 17 00:00:00 2001 From: Ota <106656898+Opi-Txm@users.noreply.github.com> Date: Sun, 5 Nov 2023 04:47:32 +0900 Subject: [PATCH 39/66] New alphabetical chapter sort (#10073) * added alphabetical chapter sorting * Deleted sort_by_alphabet and re-utilized action_sort_alpha * Accidentally deleted wrong string. Now solved * Accidentally deleted wrong string. Now solved Deleted sort_by_source instead of sort_by_alphabet in strings.xml. Now reverted. * Alphabetical sorting now uses Collator * Clean up repeated Collator instances --------- Co-authored-by: arkon --- .../interactor/GetSourcesWithFavoriteCount.kt | 9 ++------- .../presentation/manga/ChapterSettingsDialog.kt | 1 + .../tachiyomi/ui/library/LibraryScreenModel.kt | 9 ++------- .../java/tachiyomi/core/util/lang/SortUtil.kt | 15 +++++++++++++++ .../domain/chapter/service/ChapterSort.kt | 5 +++++ .../java/tachiyomi/domain/manga/model/Manga.kt | 1 + 6 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 core/src/main/java/tachiyomi/core/util/lang/SortUtil.kt diff --git a/app/src/main/java/eu/kanade/domain/source/interactor/GetSourcesWithFavoriteCount.kt b/app/src/main/java/eu/kanade/domain/source/interactor/GetSourcesWithFavoriteCount.kt index 8ca143cc1..c37be75aa 100644 --- a/app/src/main/java/eu/kanade/domain/source/interactor/GetSourcesWithFavoriteCount.kt +++ b/app/src/main/java/eu/kanade/domain/source/interactor/GetSourcesWithFavoriteCount.kt @@ -3,12 +3,11 @@ package eu.kanade.domain.source.interactor import eu.kanade.domain.source.service.SourcePreferences import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine +import tachiyomi.core.util.lang.compareToWithCollator import tachiyomi.domain.source.model.Source import tachiyomi.domain.source.repository.SourceRepository import tachiyomi.source.local.isLocal -import java.text.Collator import java.util.Collections -import java.util.Locale class GetSourcesWithFavoriteCount( private val repository: SourceRepository, @@ -31,17 +30,13 @@ class GetSourcesWithFavoriteCount( direction: SetMigrateSorting.Direction, sorting: SetMigrateSorting.Mode, ): java.util.Comparator> { - val locale = Locale.getDefault() - val collator = Collator.getInstance(locale).apply { - strength = Collator.PRIMARY - } val sortFn: (Pair, Pair) -> Int = { a, b -> when (sorting) { SetMigrateSorting.Mode.ALPHABETICAL -> { when { a.first.isStub && b.first.isStub.not() -> -1 b.first.isStub && a.first.isStub.not() -> 1 - else -> collator.compare(a.first.name.lowercase(locale), b.first.name.lowercase(locale)) + else -> a.first.name.lowercase().compareToWithCollator(b.first.name.lowercase()) } } SetMigrateSorting.Mode.TOTAL -> { diff --git a/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt index b90a86fa5..dd4b29c72 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt @@ -144,6 +144,7 @@ private fun ColumnScope.SortPage( R.string.sort_by_source to Manga.CHAPTER_SORTING_SOURCE, R.string.sort_by_number to Manga.CHAPTER_SORTING_NUMBER, R.string.sort_by_upload_date to Manga.CHAPTER_SORTING_UPLOAD_DATE, + R.string.action_sort_alpha to Manga.CHAPTER_SORTING_ALPHABET, ).map { (titleRes, mode) -> SortItem( label = stringResource(titleRes), 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 0120abcfc..fabfaa4b0 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 @@ -41,6 +41,7 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update import tachiyomi.core.preference.CheckboxState import tachiyomi.core.preference.TriState +import tachiyomi.core.util.lang.compareToWithCollator import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.withIOContext @@ -65,9 +66,7 @@ import tachiyomi.domain.track.model.Track import tachiyomi.source.local.isLocal import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import java.text.Collator import java.util.Collections -import java.util.Locale /** * Typealias for the library manga, using the category as keys, and list of manga as values. @@ -243,12 +242,8 @@ class LibraryScreenModel( // Map> trackMap: Map>, ): LibraryMap { - val locale = Locale.getDefault() - val collator = Collator.getInstance(locale).apply { - strength = Collator.PRIMARY - } val sortAlphabetically: (LibraryItem, LibraryItem) -> Int = { i1, i2 -> - collator.compare(i1.libraryManga.manga.title.lowercase(locale), i2.libraryManga.manga.title.lowercase(locale)) + i1.libraryManga.manga.title.lowercase().compareToWithCollator(i2.libraryManga.manga.title.lowercase()) } val defaultTrackerScoreSortValue = -1.0 diff --git a/core/src/main/java/tachiyomi/core/util/lang/SortUtil.kt b/core/src/main/java/tachiyomi/core/util/lang/SortUtil.kt new file mode 100644 index 000000000..03c15d43b --- /dev/null +++ b/core/src/main/java/tachiyomi/core/util/lang/SortUtil.kt @@ -0,0 +1,15 @@ +package tachiyomi.core.util.lang + +import java.text.Collator +import java.util.Locale + +private val collator by lazy { + val locale = Locale.getDefault() + Collator.getInstance(locale).apply { + strength = Collator.PRIMARY + } +} + +fun String.compareToWithCollator(other: String): Int { + return collator.compare(this, other) +} 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 45f302455..d55c51334 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterSort.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterSort.kt @@ -1,5 +1,6 @@ package tachiyomi.domain.chapter.service +import tachiyomi.core.util.lang.compareToWithCollator import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.model.Manga @@ -23,6 +24,10 @@ fun getChapterSort( true -> { c1, c2 -> c2.dateUpload.compareTo(c1.dateUpload) } false -> { c1, c2 -> c1.dateUpload.compareTo(c2.dateUpload) } } + Manga.CHAPTER_SORTING_ALPHABET -> when (sortDescending) { + true -> { c1, c2 -> c2.name.compareToWithCollator(c1.name) } + false -> { c1, c2 -> c1.name.compareToWithCollator(c2.name) } + } else -> throw NotImplementedError("Invalid chapter sorting method: ${manga.sorting}") } } diff --git a/domain/src/main/java/tachiyomi/domain/manga/model/Manga.kt b/domain/src/main/java/tachiyomi/domain/manga/model/Manga.kt index 07451c05b..f694355a4 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/model/Manga.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/model/Manga.kt @@ -85,6 +85,7 @@ data class Manga( const val CHAPTER_SORTING_SOURCE = 0x00000000L const val CHAPTER_SORTING_NUMBER = 0x00000100L const val CHAPTER_SORTING_UPLOAD_DATE = 0x00000200L + const val CHAPTER_SORTING_ALPHABET = 0x00000300L const val CHAPTER_SORTING_MASK = 0x00000300L const val CHAPTER_DISPLAY_NAME = 0x00000000L From 8644d90bd4572330e720c1eb8b64e3f323bbd709 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 4 Nov 2023 16:11:43 -0400 Subject: [PATCH 40/66] Bump dependencies --- app/src/main/java/eu/kanade/tachiyomi/util/PkceUtil.kt | 8 ++++---- gradle/libs.versions.toml | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/PkceUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/PkceUtil.kt index e8d165f57..9699a7e9f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/PkceUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/PkceUtil.kt @@ -1,15 +1,15 @@ package eu.kanade.tachiyomi.util -import android.util.Base64 import java.security.SecureRandom +import java.util.Base64 object PkceUtil { - private const val PKCE_BASE64_ENCODE_SETTINGS = Base64.NO_WRAP or Base64.NO_PADDING or Base64.URL_SAFE - fun generateCodeVerifier(): String { val codeVerifier = ByteArray(50) SecureRandom().nextBytes(codeVerifier) - return Base64.encodeToString(codeVerifier, PKCE_BASE64_ENCODE_SETTINGS) + return Base64.getUrlEncoder() + .withoutPadding() + .encodeToString(codeVerifier) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8753f7a07..919ac9ce4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -aboutlib_version = "10.9.1" +aboutlib_version = "10.9.2" okhttp_version = "5.0.0-alpha.11" shizuku_version = "12.2.0" sqlite = "2.4.0" @@ -9,7 +9,7 @@ voyager = "1.0.0-rc08" richtext = "0.17.0" [libraries] -desugar = "com.android.tools:desugar_jdk_libs:2.0.3" +desugar = "com.android.tools:desugar_jdk_libs:2.0.4" android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2" google-services-gradle = "com.google.gms:google-services:4.4.0" @@ -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.2" +kotest-assertions = "io.kotest:kotest-assertions-core:5.8.0" mockk = "io.mockk:mockk:1.13.8" voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } From 4a2ee0b5963953e24b9370fe2b867271e5f74f39 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sat, 4 Nov 2023 21:37:50 +0100 Subject: [PATCH 41/66] Translations update from Hosted Weblate (#10089) 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/de/ 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/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/ne/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/ 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/th/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/ 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: Blue Co-authored-by: Dexroneum Co-authored-by: FateXBlood Co-authored-by: Giorgio Sanna Co-authored-by: Hiroshi Co-authored-by: InfinityDouki56 Co-authored-by: La prière Co-authored-by: Lyfja Co-authored-by: Milo Ivir Co-authored-by: Uzuki Shimamura Co-authored-by: Zero O Co-authored-by: abc0922001 Co-authored-by: altinat Co-authored-by: gallegonovato Co-authored-by: winver --- i18n/src/main/res/values-ar/strings.xml | 5 ++ i18n/src/main/res/values-de/strings.xml | 13 ++- i18n/src/main/res/values-es/strings.xml | 14 +++- i18n/src/main/res/values-fil/strings.xml | 15 ++-- i18n/src/main/res/values-hr/strings.xml | 4 + i18n/src/main/res/values-it/strings.xml | 11 +-- i18n/src/main/res/values-ja/strings.xml | 90 +++++++++++---------- i18n/src/main/res/values-ne/strings.xml | 14 +++- i18n/src/main/res/values-nl/strings.xml | 47 +++++++---- i18n/src/main/res/values-pt-rBR/strings.xml | 2 + i18n/src/main/res/values-ru/strings.xml | 18 +++-- i18n/src/main/res/values-th/strings.xml | 12 ++- i18n/src/main/res/values-uk/strings.xml | 2 + i18n/src/main/res/values-zh-rCN/strings.xml | 16 ++-- i18n/src/main/res/values-zh-rTW/strings.xml | 14 +++- 15 files changed, 179 insertions(+), 98 deletions(-) diff --git a/i18n/src/main/res/values-ar/strings.xml b/i18n/src/main/res/values-ar/strings.xml index da4b33af0..6c61e4b9d 100644 --- a/i18n/src/main/res/values-ar/strings.xml +++ b/i18n/src/main/res/values-ar/strings.xml @@ -882,4 +882,9 @@ إعدادات التطبيق ما استطاع محدِّد الملفات من إدخال الملف في التطبيق البيانات والتخزين + أبدًا + يخفِّف الحرق في شاشات الحبر + آخر احتياط تلقائي: %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 560b38339..702ce8916 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -135,8 +135,8 @@ Datensicherung wiederherstellen Bibliothek mit Hilfe einer Datensicherung wiederherstellen Sicherungsspeicherort - Datensicherungshäufigkeit - Maximale Datensicherungen + Automatische Datensicherungshäufigkeit + Maximale Anzahl automatischer Datensicherungen Datensicherung erstellt Wiederherstellen abgeschlossen Was möchtest du sichern\? @@ -434,7 +434,7 @@ %1$s Kapitel Erfordert einen Neustart der App, um wirksam zu werden - Netzwerk + Vernetzung Tippzonen umkehren Beide Vertikal @@ -704,7 +704,7 @@ Quellen, Erweiterungen, globale Suche Ups! Absturzprotokolle ausgeben, Akkuverbrauch-Optimierung - Manuelle und automatische Datensicherungen + Manuelle und automatische Datensicherungen, Speicherplatz %s ist auf einen unerwarteten Fehler gestoßen. Wir empfehlen dir, die Absturzprotokolle in unserem Support-Kanal auf Discord zu teilen. App-Sperre, sicherer Bildschirm Unbekannter Titel @@ -817,4 +817,9 @@ Kategorien sortieren Möchtest du die Kategorien alphabetisch sortieren\? Dateiauswahl konnte keine Datei an die App zurückgeben + Nie + Reduziert Ghosting auf E-Papier-Displays + Zuletzt automatisch gesichert: %s + Bei Umblättern weiß aufleuchten + Daten und Speicher \ 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 e9062da65..1ce7cdfc5 100644 --- a/i18n/src/main/res/values-es/strings.xml +++ b/i18n/src/main/res/values-es/strings.xml @@ -237,8 +237,8 @@ Restaurar copia de seguridad Restaurar la biblioteca a partir de una copia de seguridad Ubicación de la copia de respaldo - Frecuencia de respaldo - Copias de seguridad máximas + Frecuencia de la copia de seguridad automática + Copias de seguridad automáticas máximas Copia de seguridad creada Restauración completada ¿De qué quieres hacer una copia de seguridad\? @@ -474,7 +474,7 @@ Desactivar Es necesario reiniciar la aplicación para que surja efecto - Red + Networking Estado desconocido Ambos Vertical @@ -747,7 +747,7 @@ Temas de colores y formatos de fecha Volcar datos del cuelgue y estado de ahorro de batería Pantalla segura y desbloqueo biométrico - Copias de seguridad manuales y automáticas + Copias de seguridad manuales y automáticas, y el espacio de almacenamiento Fuentes, extensiones y búsqueda global ¡Vaya! Reiniciar la aplicación @@ -864,4 +864,10 @@ Ordenar categorías ¿Quieres ordenar las categorías de forma alfabética\? La pantalla de selección de archivos no ha devuelto ningún archivo + Nunca + Reducir el ghosting en las pantallas de tinta electrónica + Última copia de seguridad automática: %s + Parpadeo en blanco al cambiar de página + Datos y almacenamiento + Almacenamiento utilizado \ 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 75437dcaf..949f28f8b 100644 --- a/i18n/src/main/res/values-fil/strings.xml +++ b/i18n/src/main/res/values-fil/strings.xml @@ -237,8 +237,8 @@ Hindi naglalaman ang backup ng kahit anong mga entry sa Aklatan. Invalid na backup Nai-backup na - Dami ng backup - Dalas ng pag-backup + Pinakamarami na awtomatikong pag-backup + Awtomatikong dalas ng pag-backup Lokasyon ng backup I-restore ang Aklatan mula sa backup I-restore ang backup @@ -434,7 +434,7 @@ Nalinis na ang mga cookie Nangangailangang buksan muli ang app para gumana Linisin ang mga cookie - Network + Networking Bigong ma-restore ang backup Kinansela ang pag-restore Inire-restore na @@ -756,7 +756,7 @@ Kopyahin sa clipboard Itago ang mga entry na nasa aklatan na - Susunod na kabanata + Sunod na kabanata Susunod na %d kabanata I-update ang kategorya @@ -814,8 +814,13 @@ Mag-ayos ng kategorya Nag-a-update ang aklatan... (%s) Gusto mo bang mag-ayos ng kategorya ayon sa alpabeto\? - Mga setting ng source + Mga setting ng pinagmula Mga setting ng app Ang file picker ay nabigo na ibalik ang file sa app Data at storage + Binabawasan ang ghosting sa mga e-ink na display + Mag-flash ng puti kada pagbabago ng pahina + Hindi kailanman + Huling awtomatikong na-back up: %s + Paggamit ng storage \ 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 15b468ea9..d62169cd6 100644 --- a/i18n/src/main/res/values-hr/strings.xml +++ b/i18n/src/main/res/values-hr/strings.xml @@ -834,4 +834,8 @@ Postavke izvora Postavke aplikacije Podaci i spremište + Nikada + Smanjuje artefakte na ekranima s e-tintom + Zadnja automatska sigurnosna kopija: %s + Zabljesni prilikom mijenjanja stranice \ 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 210e03ed4..f9836537d 100644 --- a/i18n/src/main/res/values-it/strings.xml +++ b/i18n/src/main/res/values-it/strings.xml @@ -243,8 +243,8 @@ Ripristina backup Ripristina la libreria da un file di backup Posizione dei backup - Frequenza dei backup - Massimo numero di backup + Frequenza dei backup automatici + Massimo numero di backup automatici Backup creato Ripristino completato Di cosa vuoi fare il backup\? @@ -623,7 +623,7 @@ Tema applicazione Autenticarsi per confermare le modifiche Predefinita - Attività in background + Attività in secondo piano Le funzioni di backup e ripristino potrebbero non funzionare correttamente se le ottimizzazioni MIUI sono disabilitate. Offrono funzioni migliorate per fonti specifiche. Le voci sono tracciate automaticamente quando aggiunte alla libreria. Servizi di tracking migliorati @@ -748,7 +748,7 @@ Fonti, estensioni, ricerca globale Modalità di lettura, aspetto, navigazione Sincronizzazione unidirezionale avanzamenti, sincronizzazione migliorata - Backup manuali e automatici + Backup manuali e automatici, spazio di archiviazione Blocco app, schermo protetto Registro arresti anomali, ottimizzazioni batteria Ops! @@ -865,5 +865,6 @@ Aggiornando libreria... (%s) Ordinamento categorie Vuoi ordinare le categorie alfabeticamente\? - Il File picker non è riuscito a restituire il file all\'app + Il selettore di file ha restituito file all\'app + Dati e archiviazione \ 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 5731595bd..9914ae3b4 100644 --- a/i18n/src/main/res/values-ja/strings.xml +++ b/i18n/src/main/res/values-ja/strings.xml @@ -28,7 +28,7 @@ コンパクトグリッド リスト ソート - 追跡 + トラッキング 拡張機能 拡張機能の情報 移行 @@ -137,8 +137,8 @@ バックアップを復元 バックアップファイルからライブラリを復元する バックアップディレクトリ - バックアップ頻度 - 最大バックアップ数 + 自動バックアップの頻度 + 最大の自動バックアップ数 バックアップが作成されました チャプタキャッシュをクリア 消去中にエラーが発生しました @@ -157,9 +157,9 @@ 削除 インストール 取り消し - 説明 + ヘルプ 前の章を既読にする - WebViewで開く + WebView で開く ビューア 同期 この拡張機能は信頼できない証明書でサインされているため、有効にされていません。 @@ -181,7 +181,7 @@ バックアップしたいのは? バックアップを復元中 バックアップを作成中 - サイズ:%1$s + サイズ: %1$s キャッシュを削除しました。%1$d件のファイルは削除されました Cookiesを削除 Cookiesを削除しました @@ -201,7 +201,7 @@ ライブラリに追加しました ライブラリから削除しました ダウンロードした章を削除してもよろしいですか? - 次をクリップボードにコピーしました: + 次をクリップボードにコピーしました: \n%1$s 第%1$s章 ダウンロード中(%1$d/%2$d) @@ -234,7 +234,7 @@ カスタム フィルタ カバーとして設定 カバーとして設定しました - ページ:%1$d + ページ: %1$d 次の章が見つかりません 画像をロードできませんでした カバーとして設定しますか? @@ -255,7 +255,7 @@ アップデート利用可能! ダウンロードがありません 最近の更新はありません - 最近に読んだ漫画がありません + 最近は何も読んでいません ライブラリは空です カテゴリーがありません。「+」をタップしてカテゴリーを追加し、ライブラリを整理できます。 ダウンロード @@ -266,15 +266,15 @@ ダウンロード一時停止済み 一般設定 読み返し中 - 未インストールのソース:%1$s - 読み終わりました: - 読んでいます: - 次: - 前: + 未インストールのソース: %1$s + 読み終わりました: + 読んでいます: + 次: + 前: 次の章がありません 前の章がありません ページをロード中… - ページのロードに失敗:%1$s + ページのロードに失敗: %1$s 長押しでアクションを表示 32ビットカラー 読み終わった章をスキップ @@ -285,7 +285,7 @@ 移行元を選択 前へ 次へ - 再ロード + 更新 ライブラリ 廃止済み この拡張機能は利用不可になったため、正常に機能しなかったり、アプリでエラーを起こしたりする恐れがあります。アンインストールすることをお勧めします。 @@ -299,11 +299,11 @@ その他 最新章の更新順 章を見る - 全てキャンセル + すべてキャンセル ダークモード オフ オン - システム設定 + システムに従う 通知設定 セキュリティとプライバシー アンロックを必要とする @@ -346,7 +346,7 @@ %1$sで完成済み %2$s件のエラーが発生しました %02d分%02d秒 - ソースがありません: + ソースがありません: バックアップにはライブラリの項目が含まれません。 バックアップファイルは無効です 一方同期の外部追跡サービスにある章の読書進捗を更新します。個別の項目の「同期」ボタンで追跡サービスを設定してください。 @@ -447,7 +447,7 @@ テーマ ライブラリへの追加日付順 エラー - ログインしていないトラッカー: + ログインしていないトラッカー: ブックマークした章の削除を許可 章を削除 この拡張機能のソースには成人向けのコンテンツが含まれる可能性があります @@ -458,7 +458,7 @@ 章が見つかりません デフォルトの章設定を更新しました - %1$s:%2$s、第%3$dページ + %1$s: %2$s、第%3$dページ デフォルトとして設定 ライブラリにあるすべての項目にも適用 デフォルト設定として保存しますか? @@ -508,8 +508,8 @@ DNS over HTTPS(DoH) 含まれているカテゴリーに入っていても、除外対象カテゴリーにある項目は更新されません。 自動ダウンロード - 下記を除外:%s - 下記を含む:%s + 下記を除外: %s + 下記を含む: %s なし 含まれているカテゴリーに入っていても、除外対象カテゴリーにある項目は更新されません。 タップで詳細を表示 @@ -534,21 +534,21 @@ 自動 操作 グレースケール - OFF - ON + オフ + オン カテゴリ別のソート設定 - 制限:%s + 制限: %s このシリーズの全項目をキャンセル ローカル ソース 横向き 縦向き 真っ黒モード - 四葉 + Yotsuba 陰陽 - + Tako ストロベリーダイキリ 黄昏 - 青林檎 + 青りんご アプリテーマ ダウンロードを開始します ダイナミック @@ -570,10 +570,10 @@ 追跡 除外されるカテゴリー メニューを自動非表示するスクロール量 - 青緑&土耳古石 + ティール & ターコイズ 外観 認証を行って変更を確認してください - 既定 + デフォルト レガシー インストーラ アプリの情報 @@ -589,7 +589,7 @@ 言語 警告 Verboseログ出力 - 警告:大量の一括ダウンロードにより、ソースは遅くなったり、Tachiyomiを接続禁止したりする恐れがあります。詳しくはタップでご覧ください。 + 警告: 大量の一括ダウンロードにより、ソースは遅くなったり、Tachiyomiを接続禁止したりする恐れがあります。詳しくはタップでご覧ください。 3日ごと Wi-Fi接続時のみ 全て更新 @@ -654,20 +654,20 @@ カスタム表紙 未インストール アプリ言語 - 香草色 + ラベンダー 説明がありません カテゴリー「%s」を削除しますか? カテゴリーを削除 - InternalError:詳しくはクラッシュ ログをご参照ください + InternalError: 詳しくはクラッシュ ログをご参照ください デフォルトのユーザーエージェント文字列 デフォルトのユーザーエージェント文字列をリセットする - 全て除去 + 全て削除 フォーマットRARv5は未対応です 最近更新されたライブラリの項目を見る アプリロックがONの時、ウィジェットは利用できません アップデートはすでに進行中です ユーザーエージェント文字列を入力してください - 海の波 + 津波 事前ダウンロード 読書中に自動でダウンロード @@ -676,7 +676,7 @@ 現在のと次の章は既にダウンロード済みの場合のみ有効です 本当に実行しますか? 多言語 - 前回のライブラリ更新:%s + 前回のライブラリ更新: %s ライブラリから「%s」を削除しようとしています 人気 ストレージ権限を持っていません @@ -693,7 +693,7 @@ 自動ダウンロード、事前ダウンロード 一方同期、高度な同期 ソース、拡張機能、グローバル検索 - 手動および自動バックアップ + 手動・自動バックアップ、ストレージ領域 アプリロック、セキュア画面 クラッシュ ログのダンプ、バッテリーの最適化 テーマ、日付と時刻の形式 @@ -733,12 +733,12 @@ カテゴリが空です アップデートアイコンに未読メッセージの件数を表示 クリップボードにコピーしました - 利用可能ですが未インストールのソース: %s + 利用可能ですが未インストールのソース: %s 重複の章をスキップ ライブラリにはもう同名の項目が存在しています。 \n \nそれでも続行しますか? - %1$s エラー:%2$s + %1$s エラー: %2$s *必須 クリップボードにコピー ライブラリにある項目を非表示 @@ -761,7 +761,7 @@ ダブルタップでズーム 間隔を設定 カスタマイズした取得間隔 - 月一回に取得(28日) + 1か月毎に取得 (28日) 次の更新予定 更新予定時間外 間隔 @@ -776,7 +776,7 @@ ごとに更新するように設定する ローカルの追跡が削除されます。 %s からも削除 - ダウンロード削除 + ダウンロードを削除 10+チェック後半 落とした\? 20歳以上後半と2ヶ月 チェック期間を過ぎました @@ -801,4 +801,10 @@ ソース設定 アプリ設定 ファイルピッカーはアプリにファイルを返せませんでした + なし + Eインク画面の焼き付きを軽減 + 前回の自動バックアップ: %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 5d594acf9..a7f888988 100644 --- a/i18n/src/main/res/values-ne/strings.xml +++ b/i18n/src/main/res/values-ne/strings.xml @@ -340,7 +340,7 @@ \n \nतपाईंले कुनै पनि छुटेको एक्सटेन्शनहरू स्थापना गर्न र तिनीहरूलाई प्रयोग गर्न पछि ट्र्याकिङ सेवाहरूमा लगइन गर्न आवश्यक हुनेछ। रिस्टोर पहिले नै प्रगतिमा छ - नेटवर्क + नेटवर्किङ ब्याकअप रिस्टोर असफल भयो तपाईंले ब्याकअपको प्रतिलिपिहरू अन्य ठाउँहरूमा पनि राख्नु पर्छ। ब्याकअपहरूमा कुनै पनि भण्डारण गरिएका पासवर्डहरू सहित संवेदनशील डेटा समावेश हुन सक्छ; साझा गर्दा होसियार । नयाँ अध्यायहरू फेला पर्यो @@ -421,8 +421,8 @@ ब्याकअप फाइलबाट पुस्तकालय रिस्टोर गर्नुहोस् ब्याकअपमा कुनै पनि पुस्तकालयका इन्ट्री समावेश छैन। ब्याकअप स्थान - ब्याकअप फ्रिक्वेन्सी - अधिकतम ब्याकअपहरू + स्वचालित ब्याकअप फ्रिक्वेन्सी + अधिकतम स्वचालित ब्याकअपहरू प्रयोग गरिएको: %1$s %d इन्ट्रीको लागि @@ -648,7 +648,7 @@ ल्याभेन्डर एप को भाषा पढ्दा स्वत: डाउनलोड गर्नुहोस् - म्यानुअल र स्वचालित ब्याकअप + म्यानुअल र स्वचालित ब्याकअप, भण्डारण स्पेस एप लक, सुरक्षित स्क्रिन थुप्रै अपडेटहरू आइकनमा नपढिएको गणना देखाउनुहोस् @@ -816,4 +816,10 @@ एप सेटिङहरू सापेक्ष टाइमस्ट्याम्पहरू \"%2$s\" को सट्टा \"%1$s\" + कहिले पनि होइन + ई-इंक स्क्रिनहरूमा गोस्टिङ घटाउँछ + पछिल्लो पटक स्वचालित ब्याकअप गरिएको: %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 8a7bfce97..55f28c819 100644 --- a/i18n/src/main/res/values-nl/strings.xml +++ b/i18n/src/main/res/values-nl/strings.xml @@ -95,7 +95,7 @@ Links Rechts Midden - Standaard draaitype + Standaardoriëntatie Vrij R G @@ -107,14 +107,14 @@ Een-na-laatste gelezen hoofdstuk Twee-na-laatste gelezen hoofdstuk Download nieuwe hoofdstukken - Diensten + Trackers Back-up maken Kan worden gebruikt om de huidige bibliotheek te herstellen Back-up herstellen Herstellen van back-up bestand Back-uplocatie - Back-upfrequentie - Maximaal aantal back-ups + Frequentie van automatische back-ups + Maximaal aantal automatische back-ups Back-up gemaakt Herstellen voltooid Wat wil je back-uppen? @@ -407,7 +407,7 @@ %d categorieën Omslagen van manga in bibliotheek bijwerken - Eenzijdige synchronisatie om voortang van hoofdstukken bij te werken bij trackingdiensten. Stel tracking in bij individuele items via de \"Tracking\"-knop. + Eenzijdige synchronisatie om voortang van hoofdstukken bij te werken bij externe trackerdiensten. Stel tracking in bij individuele items via de \"Tracking\"-knop. Deze extensie behoort niet tot de officiële Tachiyomi extensielijst. Niet officieel Controleer bij het bijwerken van de bibliotheek op nieuwe omslag en details @@ -434,7 +434,7 @@ %1$s hoofdstukken Herstart van de app nodig om van kracht te worden - Netwerk + Netwerken Beiden Verticaal Horizontaal @@ -530,7 +530,7 @@ Incognitomodus uitschakelen Liggend Staand - Draaitype + Oriëntatie Automatisch Acties Grijstinten @@ -564,8 +564,8 @@ Nachtschemering Groene Appel Appthema - Diensten die uitgebreidere functionaliteit bieden voor bepaalde bronnen. Het tracken van items gebeurt automatisch wanneer je deze toevoegt aan je bibliotheek. - Verbeterde diensten + Bieden uitgebreidere functionaliteit voor bepaalde bronnen. Het tracken van items gebeurt automatisch wanneer je deze toevoegt aan je bibliotheek. + Verbeterde trackers Dynamisch Gids voor beginners Help met vertalen @@ -595,7 +595,7 @@ Verouderd Shizuku wordt niet uitgevoerd Installatieprogramma - Je zou kopies van back-ups ook in andere plaatsen moeten hebben. + Je zou kopies van back-ups ook in andere plaatsen moeten hebben. Back-ups kunnen gevoelige data zoals opgeslagen wachtwoorden bevatten; let op met delen. Alleen via Wi-Fi Uitgebreide logging Waarschuwing: grote updates schaden bronnen en kunnen leiden tot slomere updates en verhoogd batterijgebruik @@ -679,7 +679,7 @@ Leesmodus, weergave, navigatie Automatische downloads, vooraf downloaden Bronnen, extensies, globaal zoeken - Handmatige en automatische back-ups + Handmatige & automatische back-ups, opslagruimte App-vergrendeling, schermbeveiliging Alle leesinstellingen teruggezet naar de standaardwaarden Kon leesinstellingen niet terugzetten naar standaardwaarden @@ -747,7 +747,7 @@ Gelicenseerd - Geen hoofdstukken te laten zien Draairichting van geroteerde brede pagina\'s omdraaien Dubbeltik om te zoomen - Log-in volgen + Tracker login Bibliotheek synchroniseren Heeft resultaten Dit zal jouw eerder geselecteerde einddatum weg halen van %s @@ -761,13 +761,13 @@ Interval aanpassen Download Index geïnvalideerd - - + 1 dag + %d dagen Maak de downloadindex ongeldig - - + %1$s hoofdstuk mist + %1$s hoofdstukken missen OK Swipe naar de linker actie @@ -808,4 +808,19 @@ 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 + Nooit + Vermindert ghosting bij e-ink schermen + Sorteer categorieën + Voor het laatst een automatische back-up gemaakt op: %s + Breng serie naar beneden + Scherm wit flitsen bij het wisselen van pagina\'s + Opslaggebruik + Bibliotheek bijwerken... (%s) + Data en opslag + Wil je de categorieën sorteren op alfabetische volgorde\? + Bestandskiezer gaf geen bestand terug aan de app + Bron-instellingen + App-instellingen + Relatieve tijdstempels + \"%1$s\" in plaats van \"%2$s\" \ 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 c3a1ae552..7005476ed 100644 --- a/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/i18n/src/main/res/values-pt-rBR/strings.xml @@ -834,4 +834,6 @@ Você deseja ordenar as categorias alfabeticamente\? O seletor de arquivos não retornou o arquivo para o aplicativo Dados e armazenamento + Reduz o efeito fantasma em telas e-ink + Flash branco ao mudar de página \ 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 ea72d69cd..d1208de33 100644 --- a/i18n/src/main/res/values-ru/strings.xml +++ b/i18n/src/main/res/values-ru/strings.xml @@ -210,8 +210,8 @@ Серии библиотеки Больше нет результатов Папка резервной копии - Частота резервных копий - Количество резервных копий + Частота автоматических резервных копий + Количество автоматических резервных копий Создать резервную копию Можно использовать для восстановления текущей библиотеки Обрезать поля @@ -728,7 +728,7 @@ Автоматическая загрузка, загрузка наперёд Односторонняя синхронизация прогресса, расширенная синхронизация Источники, расширения, глобальный поиск - Ручные и автоматические резервные копий + Ручные и автоматические резервные копий, хранилище Блокировка приложения, защита экрана Выгрузка журнала с ошибками, оптимизация батареи Ой, ошибочка вышла! @@ -805,13 +805,13 @@ Двойное нажатие для увеличения %d в ряд Настраиваемый интервал получения - Месячное получение (28 дней) - Заброшено\? Прошлые 20+ дней и 2 месяца + Месячная проверка (28 дней) + Заброшено\? Прошедшие 20+ дней и 2 месяца Интервалы Оценивать каждые Настроить интервал Задать интервал - Проверка поздних 10+ дней + Проверка прошедших 10+ дней Срок проверки истёк Следующее ожидамое обновление За пределами ожидаемого периода выпуска @@ -849,4 +849,10 @@ Сортировать категории Хотите ли вы сортировать категории по алфавиту\? Приложению для выбора файлов не удалось вернуть путь файла в Tachiyomi + Данные и хранение + Никогда + Уменьшает артефакты у экранов e-ink + Последнее автоматическое резервное копирование: %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 ee25ac2d8..55d05b2ca 100644 --- a/i18n/src/main/res/values-th/strings.xml +++ b/i18n/src/main/res/values-th/strings.xml @@ -163,8 +163,8 @@ เรียกคืนค่าการสำรองข้อมูล เรียกคืนค่าคลังจากแฟ้มข้อมูลสำรอง ตําแหน่งที่ตั้งข้อมูลสํารอง - ความถี่ในการสำรองข้อมูล - จำนวนการสำรองข้อมูลสูงสุด + ความถี่ในการสำรองข้อมูลอัตโนมัติ + จำนวนการสำรองข้อมูลอัตโนมัติสูงสุด สร้างการสำรองข้อมูลแล้ว คืนค่าเสร็จสมบูรณ์ ต้องการสำรองข้อมูลใดบ้าง\? @@ -688,7 +688,7 @@ การดาวน์โหลดอัตโนมัติ, การดาวน์โหลดล่วงหน้า การประมวลผลซิงก์ทางเดียง, เสริมการวิงก์ แหล่งที่มา, ส่วนขยาย, การค้นหาทั้งหมด - การสำรองข้อมูลด้วยตนเองและอัตโนมัติ + การสำรองข้อมูลและพื้นที่เก็บข้อมูลด้วยตนเองและอัตโนมัติ การล็อกแอป, หน้าจอความปลอดภัย ดัมพ์บันทึกข้อขัดข้อง, การเพิ่มประสิทธิภาพแบตเตอรี่ เกิดความผิดพลาด! @@ -801,4 +801,10 @@ การตั้งค่าแหล่งที่มา การตั้งค่าแอป เครื่องมือเลือกไฟล์ไม่สามารถส่งต่อไฟล์ไปยังแอปได้ + ไม่เลย + ลดภาพซ้อนบนจอแสดงผล E-Ink + สำรองข้อมูลอัตโนมัติครั้งล่าสุด: %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 bdef440a1..53fbdbb7e 100644 --- a/i18n/src/main/res/values-uk/strings.xml +++ b/i18n/src/main/res/values-uk/strings.xml @@ -842,4 +842,6 @@ Не вдалося досягти %s Відносні позначки часу \"%1$s\" замість \"%2$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 ce0c97f31..51d3299dd 100644 --- a/i18n/src/main/res/values-zh-rCN/strings.xml +++ b/i18n/src/main/res/values-zh-rCN/strings.xml @@ -97,11 +97,11 @@ 不可信 卸载 不可信的插件 - 此插件的证书并不可信,且尚未被开启。 + 此插件使用不受信任的证书签名且尚未激活。 \n -\n恶意的插件可能会读取储存在 Tachiyomi 中的任何登录凭据或执行任意代码。 +\n恶意插件可以读取任何存储的登录凭据或执行任意代码。 \n -\n信任这个证书,即代表你愿意承担上述风险。 +\n信任此证书即代表你愿意承担上述风险。 全屏 页面过渡动画 双击动画速度 @@ -400,7 +400,7 @@ 缓解色带问题,但可能会影响性能 刷新书架封面 将阅读进度上传到进度记录平台。在作品页面点击“进度记录”按钮即可设置。 - 此插件不是 Tachiyomi 官方插件 + 此插件并非源自官方目录 非官方 按上传日期 数据 @@ -690,7 +690,7 @@ 自动下载 • 预先下载 阅读进度上传 • 增强同步 导出崩溃日志 • 电池优化 - 手动备份 • 自动备份 + 手动备份 • 自动备份,存储空间 应用锁 • 隐私界面 图源 • 插件 • 全局搜索 阅读模式 • 显示 • 翻页 @@ -801,4 +801,10 @@ 文件选择器无法将文件恢复至应用 相对时间戳 以\"%1$s\" 表示 \"%2$s\" + 从不 + 减少电子墨水屏上的重影 + 上次自动备份:%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 57c60af4d..b01e748b2 100644 --- a/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/i18n/src/main/res/values-zh-rTW/strings.xml @@ -117,7 +117,7 @@ 建立備份 還原備份 備份位置 - 備份頻率 + 自動備份頻率 已建立備份 還原成功 哪些項目需要備份? @@ -267,7 +267,7 @@ \n \n若選擇信任該憑證,即表示你願意承擔上述風險。 最後閱畢的章節 - 最大備份保留數 + 最大自動備份數量 您確定要這樣做嗎?未收藏的漫畫的閱讀進度和章節會被刪除 新上架 歷程 @@ -400,7 +400,7 @@ %d 個類別 需要重新啟動應用程式以套用 - 網路 + 網路設定 全部 垂直 水平 @@ -686,7 +686,7 @@ 主題、日期格式 自動下載、預先下載 單向進度同步、增強式同步 - 手動備份、自動備份 + 手動與自動備份,儲存空間 上鎖應用程式、防窺畫面 傾印當機記錄、電池效能最佳化 重新啟動應用程式 @@ -801,4 +801,10 @@ 欲依照字母順序排列類別嗎? 來源設定 無法將選定的檔案傳回給應用程式 + 永不 + 減少電子墨水螢幕上的殘影 + 最後一次自動備份:%s + 頁面轉換時閃白 + 資料與儲存空間 + 儲存空間佔用 \ No newline at end of file From 4b225a4ff155dc019cf4db00b59d449e0db521ab Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 4 Nov 2023 16:37:03 -0400 Subject: [PATCH 42/66] Revert "Always save pages/covers in subfolders" This reverts commit 8568d5d6c3ceae0084a350906b330f23dab571e1. Closes #10052 --- .../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-ar/strings.xml | 2 ++ 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 | 2 ++ i18n/src/main/res/values-ceb/strings.xml | 2 ++ i18n/src/main/res/values-cs/strings.xml | 2 ++ i18n/src/main/res/values-cv/strings.xml | 2 ++ i18n/src/main/res/values-de/strings.xml | 2 ++ i18n/src/main/res/values-el/strings.xml | 2 ++ i18n/src/main/res/values-eo/strings.xml | 1 + i18n/src/main/res/values-es/strings.xml | 2 ++ 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 | 2 ++ 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 | 2 ++ i18n/src/main/res/values-ja/strings.xml | 2 ++ i18n/src/main/res/values-jv/strings.xml | 2 ++ i18n/src/main/res/values-kk/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 | 2 ++ i18n/src/main/res/values-ms/strings.xml | 2 ++ 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 | 2 ++ i18n/src/main/res/values-pl/strings.xml | 2 ++ i18n/src/main/res/values-pt-rBR/strings.xml | 2 ++ 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 | 2 ++ i18n/src/main/res/values-sa/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 | 2 ++ i18n/src/main/res/values-sv/strings.xml | 2 ++ 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 | 2 ++ i18n/src/main/res/values-vi/strings.xml | 2 ++ i18n/src/main/res/values-zh-rCN/strings.xml | 2 ++ i18n/src/main/res/values-zh-rTW/strings.xml | 2 ++ i18n/src/main/res/values/strings.xml | 2 ++ 61 files changed, 133 insertions(+), 6 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 750f8138d..14e0fd9df 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 @@ -347,6 +347,11 @@ 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 60446da02..3cdce975d 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 @@ -168,12 +168,19 @@ sealed class Image( } sealed interface Location { - data class Pictures(val relativePath: String) : Location + data class Pictures private constructor(val relativePath: String) : Location { + companion object { + fun create(relativePath: String = ""): Pictures { + return Pictures(relativePath) + } + } + } 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), @@ -187,7 +194,6 @@ 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 f1a7377e1..67b98556f 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 = "cover", - location = if (temp) Location.Cache else Location.Pictures(manga.title), + name = manga.title, + location = if (temp) Location.Cache else Location.Pictures.create(), ), ) } 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 c0a252b35..4b3cbf0d8 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 @@ -758,14 +758,17 @@ class ReaderViewModel @JvmOverloads constructor( val filename = generateFilename(manga, page) - // Copy file in background + // Pictures directory. + val relativePath = if (readerPreferences.folderPerManga().get()) DiskUtil.buildValidFilename(manga.title) else "" + + // Copy file in background. viewModelScope.launchNonCancellable { try { val uri = imageSaver.save( image = Image.Page( inputStream = page.stream!!, name = filename, - location = Location.Pictures(DiskUtil.buildValidFilename(manga.title)), + location = Location.Pictures.create(relativePath), ), ) 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 ab38911f8..72f2436f4 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 @@ -56,6 +56,8 @@ 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-ar/strings.xml b/i18n/src/main/res/values-ar/strings.xml index 6c61e4b9d..30e6fdae3 100644 --- a/i18n/src/main/res/values-ar/strings.xml +++ b/i18n/src/main/res/values-ar/strings.xml @@ -566,6 +566,8 @@ رأسي التدوير تلقائيًّا + إنشاء مجلدات وفقا لعنوان الإدخالات + حفظ الصفحات في مجلدات منفصلة الإجراءات تدرج رمادي إستثناء: %s 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 5dd7cc756..a34bc4886 100644 --- a/i18n/src/main/res/values-b+es+419/strings.xml +++ b/i18n/src/main/res/values-b+es+419/strings.xml @@ -523,6 +523,7 @@ Rotación Derecha Izquierda + Crea carpetas según el título del manga Escala de grises Está versión de Android ya no está soportada Falló al copiar en el portapapeles @@ -533,6 +534,7 @@ \nNecesitarás instalar cualquier extensión que falte e iniciar sesión en los servicios de seguimiento para utilizarlos. Anterior Siguiente + Guardar páginas en carpetas separadas Acciones Partir en dos las páginas anchas Mostrar brevemente cuando se abre el lector diff --git a/i18n/src/main/res/values-be/strings.xml b/i18n/src/main/res/values-be/strings.xml index 8caa4e85f..09af8aa0e 100644 --- a/i18n/src/main/res/values-be/strings.xml +++ b/i18n/src/main/res/values-be/strings.xml @@ -227,6 +227,8 @@ Шэры Белы Колер фону + Ствараць тэчкі ў адпаведнасці з назвай мангі + Захоўваць старонкі ў асобныя тэчкі Паказаць пры доўгім націску Дзеяння Абодва diff --git a/i18n/src/main/res/values-bg/strings.xml b/i18n/src/main/res/values-bg/strings.xml index 0491ef282..b6c2744e6 100644 --- a/i18n/src/main/res/values-bg/strings.xml +++ b/i18n/src/main/res/values-bg/strings.xml @@ -536,6 +536,7 @@ Да L-образно Kindle-подобно + Създава папки според заглавието на мангата Автоматично Схема на навигацията Преди @@ -583,6 +584,7 @@ Черно-бяло Инвертирай докосване Действия + Запазвай страниците в отделни папки Дясно и Ляво Ориентация Портрет diff --git a/i18n/src/main/res/values-bn/strings.xml b/i18n/src/main/res/values-bn/strings.xml index 1cbf20edd..400caa402 100644 --- a/i18n/src/main/res/values-bn/strings.xml +++ b/i18n/src/main/res/values-bn/strings.xml @@ -543,6 +543,8 @@ পরবর্তী পূর্ববর্তী স্বয়ংক্রিয় + মাঙ্গা শিরোনাম অনুযায়ী ফোল্ডার তৈরি করে + পৃষ্ঠাগুলি পৃথক ফোল্ডারে সংরক্ষণ করুন ক্রিয়া উল্টানো ধূসর স্কেল diff --git a/i18n/src/main/res/values-ca/strings.xml b/i18n/src/main/res/values-ca/strings.xml index 6a88ec38b..835229167 100644 --- a/i18n/src/main/res/values-ca/strings.xml +++ b/i18n/src/main/res/values-ca/strings.xml @@ -528,6 +528,8 @@ Següent Anterior Automàtic + Crea carpetes segons el títol dels elements + Desa les pàgines en carpetes separades Accions Escala de grisos Mostra breument les zones de toc en obrir el lector diff --git a/i18n/src/main/res/values-ceb/strings.xml b/i18n/src/main/res/values-ceb/strings.xml index 03d06c1b0..75f208b1a 100644 --- a/i18n/src/main/res/values-ceb/strings.xml +++ b/i18n/src/main/res/values-ceb/strings.xml @@ -240,6 +240,8 @@ Pahigda Ang duha Mga aksyon + I-save ang mga panid sa lainlaing mga folder + Naghimo ug mga folder sumala sa titulo sa manga Puti Gray Itom diff --git a/i18n/src/main/res/values-cs/strings.xml b/i18n/src/main/res/values-cs/strings.xml index 74873157e..5c92bea30 100644 --- a/i18n/src/main/res/values-cs/strings.xml +++ b/i18n/src/main/res/values-cs/strings.xml @@ -536,6 +536,8 @@ Na šířku Na výšku Otáčení + Vytváří složky podle názvu položky + Uložit stránky do samostatných složek Akce Vpravo Vlevo diff --git a/i18n/src/main/res/values-cv/strings.xml b/i18n/src/main/res/values-cv/strings.xml index 65ffa0e9e..b85cc91d7 100644 --- a/i18n/src/main/res/values-cv/strings.xml +++ b/i18n/src/main/res/values-cv/strings.xml @@ -522,6 +522,8 @@ Тӑрӑх Урлӑ Урлӑ-тӑрӑх тӗсӗ + Папкӑсене сери ячӗпе туни + Елсене уйрӑм папкӑсенче упрамалла Тӑвӑмсем Пусма вырӑнсене вулӑш уҫӑ чухне кӑтартмалла Йӑнӑшсене кӑтарт diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml index 702ce8916..f955b1e54 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -529,6 +529,8 @@ Kopieren in die Zwischenablage fehlgeschlagen Querformat Hochformat + Erstellt Ordner nach dem Titel der Einträge + Speichere Seiten in separate Ordner Ausrichtung Aktionen Graustufen diff --git a/i18n/src/main/res/values-el/strings.xml b/i18n/src/main/res/values-el/strings.xml index 520d78f1f..3efbebd71 100644 --- a/i18n/src/main/res/values-el/strings.xml +++ b/i18n/src/main/res/values-el/strings.xml @@ -529,6 +529,8 @@ Απέτυχε η αντιγραφή στο πρόχειρο Οριζόντια Κατακόρυφα + Δημιουργεί φακέλους σύμφωνα με τον τίτλο των καταχωρήσεων + Αποθήκευση σελίδων σε ξεχωριστούς φακέλους Ενέργειες Περιστροφή Κλίμακα του γκρι diff --git a/i18n/src/main/res/values-eo/strings.xml b/i18n/src/main/res/values-eo/strings.xml index ae6ffee77..0de7976c8 100644 --- a/i18n/src/main/res/values-eo/strings.xml +++ b/i18n/src/main/res/values-eo/strings.xml @@ -455,6 +455,7 @@ Restaŭri savkopion Ŝanĝspuri Servoj + Kreas dosierujojn laŭ mangaaj titoloj Inversigi laŭtec-butonojn Inversigita Du-paĝa divido diff --git a/i18n/src/main/res/values-es/strings.xml b/i18n/src/main/res/values-es/strings.xml index 1ce7cdfc5..3c99d7c7e 100644 --- a/i18n/src/main/res/values-es/strings.xml +++ b/i18n/src/main/res/values-es/strings.xml @@ -572,6 +572,8 @@ Mostrar el número de elementos Fecha de obtención del capítulo Tipo de rotación + Crea carpetas según el título de los elementos + Guardar páginas en carpetas separadas Acciones Escala de grises Es posible que las funciones de copia de respaldo y restauración no funcionen correctamente si la opción «Optimización de MIUI» está desactivada. diff --git a/i18n/src/main/res/values-eu/strings.xml b/i18n/src/main/res/values-eu/strings.xml index 4cef824bb..dc140017b 100644 --- a/i18n/src/main/res/values-eu/strings.xml +++ b/i18n/src/main/res/values-eu/strings.xml @@ -355,6 +355,8 @@ %1$s Kapituluak Mantendu pantaila piztuta Saltatu irakurriak bezala markatutako kapituluak + Gorde orrialdeak karpeta ezberdinetan + Sortu karpetak manga izenburuaren arabera Altua Saltatu iragazitako kapituluak Bolumen-teklak diff --git a/i18n/src/main/res/values-fa/strings.xml b/i18n/src/main/res/values-fa/strings.xml index bddb1ba85..de2928aa1 100644 --- a/i18n/src/main/res/values-fa/strings.xml +++ b/i18n/src/main/res/values-fa/strings.xml @@ -493,11 +493,13 @@ راست قدیمی نصب کننده + ساخت پوشه بر اساس عنوان ورودی آپدیت همگی فعالیت در پس زمینه مجموع ورودی ها پیش فرض دنبال شده + ذخیره صفحات در پوشه های جداگانه هیچ مورد مشابهی پیدا نشد در حال نصب کردن افزونه … دریافت لیست افزونه ها ناموفق بود diff --git a/i18n/src/main/res/values-fi/strings.xml b/i18n/src/main/res/values-fi/strings.xml index 7d0192a04..86444f7e0 100644 --- a/i18n/src/main/res/values-fi/strings.xml +++ b/i18n/src/main/res/values-fi/strings.xml @@ -529,6 +529,8 @@ Kopiointi leikepöydälle epäonnistui Vaakatasossa Pystysuunnassa + Luo kansioita manga-otsikon mukaan + Tallenna sivut erillisiin kansioihin Toiminnot Kierron tyyppi Harmaasävy diff --git a/i18n/src/main/res/values-fil/strings.xml b/i18n/src/main/res/values-fil/strings.xml index 949f28f8b..a61be47a9 100644 --- a/i18n/src/main/res/values-fil/strings.xml +++ b/i18n/src/main/res/values-fil/strings.xml @@ -529,6 +529,8 @@ Bigong makopya sa clipboard Pahiga Patayo + Gumagawa ng mga folder ayon sa pamagat ng entry + I-save ang mga pahina sa folder nila Gawain Pag-ikot Maabo diff --git a/i18n/src/main/res/values-fr/strings.xml b/i18n/src/main/res/values-fr/strings.xml index 1bb270c1c..8a7248055 100644 --- a/i18n/src/main/res/values-fr/strings.xml +++ b/i18n/src/main/res/values-fr/strings.xml @@ -575,6 +575,8 @@ Paysage Portrait Désactiver le mode incognito + Crée des dossiers en fonction du titre des entrées + Enregistrer les pages dans des dossiers séparés Actions Niveaux de gris Aucune correspondance trouvée diff --git a/i18n/src/main/res/values-gl/strings.xml b/i18n/src/main/res/values-gl/strings.xml index 9a7ef4d40..37f61c5bd 100644 --- a/i18n/src/main/res/values-gl/strings.xml +++ b/i18n/src/main/res/values-gl/strings.xml @@ -272,6 +272,8 @@ Invertido Vertical Ambos + Gardar as páxinas en carpetas separadas + Crea carpetas segundo o título dos elementos Vertical Horizontal Mellora o rendemento do lector diff --git a/i18n/src/main/res/values-he/strings.xml b/i18n/src/main/res/values-he/strings.xml index bcdcf1d3c..daf3a2728 100644 --- a/i18n/src/main/res/values-he/strings.xml +++ b/i18n/src/main/res/values-he/strings.xml @@ -469,6 +469,7 @@ רצועה מוארכת עם רווחים סידור עמודים מאונך הפוך + שמור דפים בתיקיות נפרדות אנכי שניהם פעולות @@ -476,6 +477,7 @@ אוטומטי אפשר מחיקת פרקים שסומנו מנוע + צור תיקיות בהתאם לכותרת הפריטים שירותים המספקים שירותים משופרים למקורות ספציפיים. פריטים יהיו במעקב אוטומטי אחרי הוספה לספרייה שלך. מקורות חסרים: קובץ גיבוי לא תקין diff --git a/i18n/src/main/res/values-hi/strings.xml b/i18n/src/main/res/values-hi/strings.xml index cb62abed9..080f72fd4 100644 --- a/i18n/src/main/res/values-hi/strings.xml +++ b/i18n/src/main/res/values-hi/strings.xml @@ -561,6 +561,7 @@ शिज़ुकु नहीं चल रहा है उल्टी काला और सफेद + आइटम के शीर्षक अनुसार फोल्डर बनाता है ट्रैकिंग गाइड उन्नत सेवाएं MIUI ऑप्टिमाइज़ेशन अक्षम होने पर बैकअप/पुनर्स्थापना ठीक से काम नहीं कर सकता है। @@ -584,6 +585,7 @@ अनुवाद में मदद करें दिनांक कवर पृष्ठ + पृष्ठों को अलग-अलग फ़ोल्डरों में सहेजें बहिष्कृत श्रेणियों की आइटम डाउनलोड नहीं की जाएंगी, भले ही वे शामिल श्रेणियों में भी हों। सिस्टम लॉग में वर्बोज़ लॉग प्रिंट करें (ऐप प्रदर्शन को कम करता है) ऐसी सेवाएँ जो विशिष्ट स्रोतों के लिए उन्नत सुविधाएँ प्रदान करती हैं। आपकी पुस्तकालय में जोड़े जाने पर आइटम को स्वचालित रूप से ट्रैक किया जाता है। diff --git a/i18n/src/main/res/values-hr/strings.xml b/i18n/src/main/res/values-hr/strings.xml index d62169cd6..47c8f888b 100644 --- a/i18n/src/main/res/values-hr/strings.xml +++ b/i18n/src/main/res/values-hr/strings.xml @@ -544,6 +544,8 @@ Deaktiviraj anonimni modus Okretanje Automatski + Stvara mape prema naslovu unosa + Spremi stranice u zasebne mape Radnje Prekini sve za ovu seriju Poglavlje nije pronađeno diff --git a/i18n/src/main/res/values-hu/strings.xml b/i18n/src/main/res/values-hu/strings.xml index 57406f7da..a0fad7fd4 100644 --- a/i18n/src/main/res/values-hu/strings.xml +++ b/i18n/src/main/res/values-hu/strings.xml @@ -406,6 +406,8 @@ Hosszú szalag lyukakkal Automatikus Szürke + Mappák létrehozása bejegyzések címe szerint + Mentse a lapokat külön mappákba Cselekmények mutatása hosszú koppintáskor Műveletek Egyik sem diff --git a/i18n/src/main/res/values-in/strings.xml b/i18n/src/main/res/values-in/strings.xml index 989ee6731..fde4d03ef 100644 --- a/i18n/src/main/res/values-in/strings.xml +++ b/i18n/src/main/res/values-in/strings.xml @@ -499,6 +499,8 @@ Lanjut Sblm Otomatis + Simpan halaman di folder terpisah + Membuat folder sesuai dengan judul entri Kecuali: %s Termasuk: %s Membagi halaman lebar diff --git a/i18n/src/main/res/values-it/strings.xml b/i18n/src/main/res/values-it/strings.xml index f9836537d..f4f86e791 100644 --- a/i18n/src/main/res/values-it/strings.xml +++ b/i18n/src/main/res/values-it/strings.xml @@ -576,7 +576,9 @@ Orizzontale Verticale Auto + Crea cartelle in base al titolo delle voci Annulla tutti per questa serie + Salva pagine in cartelle separate Azioni Scala di grigi Nessun risultato trovato diff --git a/i18n/src/main/res/values-ja/strings.xml b/i18n/src/main/res/values-ja/strings.xml index 9914ae3b4..353d4fabd 100644 --- a/i18n/src/main/res/values-ja/strings.xml +++ b/i18n/src/main/res/values-ja/strings.xml @@ -532,6 +532,8 @@ 追跡ガイド 画面向き 自動 + 項目のタイトルに基づいてフォルダを作成 + 別々のフォルダにページを保存 操作 グレースケール オフ diff --git a/i18n/src/main/res/values-jv/strings.xml b/i18n/src/main/res/values-jv/strings.xml index 4dab8b4dc..6f33de6b8 100644 --- a/i18n/src/main/res/values-jv/strings.xml +++ b/i18n/src/main/res/values-jv/strings.xml @@ -294,6 +294,7 @@ Kacepetan animasi tutul kaping pindho Walik zona tutul Horisontal + Nggawe folder miturut judhul manga Numpuki Layar Pandhu arah @@ -314,6 +315,7 @@ Layar urip terus Aksi Tampilake ing tunyuk dawa + Simpen kaca menyang folder sing kapisah Statistik Lokal Diwiwiti diff --git a/i18n/src/main/res/values-kk/strings.xml b/i18n/src/main/res/values-kk/strings.xml index e3f9cc37c..ad9b5e435 100644 --- a/i18n/src/main/res/values-kk/strings.xml +++ b/i18n/src/main/res/values-kk/strings.xml @@ -290,6 +290,7 @@ Ені бойынша Бастапқы мөлшері Кері портрет + Бумаларды жазбалар атауына сәйкес жасау Көлденең Бүйірлік шегініс Қ @@ -344,6 +345,7 @@ Соңғы оқылғаннан төртінші тарау Қызметтер Сақтық көшірме жасау + Беттерді бөлек бумаларға сақтау Түсқағаз Алдыңғ Биіктігі бойынша diff --git a/i18n/src/main/res/values-kn/strings.xml b/i18n/src/main/res/values-kn/strings.xml index 9f73b9a18..ec5f2f09b 100644 --- a/i18n/src/main/res/values-kn/strings.xml +++ b/i18n/src/main/res/values-kn/strings.xml @@ -547,6 +547,8 @@ ಉದ್ದವಾದ ಪುಟ ತಿರುಗುವಿಕೆಯ ಪ್ರಕಾರ ಸ್ವಯಂಚಾಲಿತ + ಮಾಂಗಾ ಶೀರ್ಷಿಕೆಗೆ ಅನುಗುಣವಾಗಿ ಫೋಲ್ಡರ್ ಗಳನ್ನು ರಚಿಸುತ್ತದೆ + ಪ್ರತ್ಯೇಕ ಫೋಲ್ಡರ್ ಗಳಲ್ಲಿ ಪುಟಗಳನ್ನು ಉಳಿಸಿ ಕ್ರಿಯೆಗಳು ಗ್ರೇಸ್ಕೇಲ್ ಆಫ diff --git a/i18n/src/main/res/values-ko/strings.xml b/i18n/src/main/res/values-ko/strings.xml index 7144abc7d..ee976315d 100644 --- a/i18n/src/main/res/values-ko/strings.xml +++ b/i18n/src/main/res/values-ko/strings.xml @@ -589,6 +589,7 @@ 읽지 않은 회차가 있는 만화를 건너 뛰었습니다 등록된 카테고리가 없습니다. + 항목 제목에 따라 폴더 생성 소스 이전 설명서 원본 소스를 선택하세요 로컬 소스 @@ -599,6 +600,7 @@ 모두 취소 이 만화의 항목을 모두 취소 앞으로 + 각각의 폴더에 페이지 저장 FAQ 및 설명서 읽지 않음 이 시리즈를 맨 위로 이동 diff --git a/i18n/src/main/res/values-lt/strings.xml b/i18n/src/main/res/values-lt/strings.xml index 19b51d0f2..792cfab3b 100644 --- a/i18n/src/main/res/values-lt/strings.xml +++ b/i18n/src/main/res/values-lt/strings.xml @@ -244,6 +244,8 @@ Vertikalus Veiksmai Parodyti ilgiau paspaudus + Išsaugoti puslapius atskiruose aplankuose + Sukuria aplankus pagal įrašo pavadinimą Fono spalva Ankstesnis Pilka diff --git a/i18n/src/main/res/values-lv/strings.xml b/i18n/src/main/res/values-lv/strings.xml index ac63f614d..068f16adf 100644 --- a/i18n/src/main/res/values-lv/strings.xml +++ b/i18n/src/main/res/values-lv/strings.xml @@ -340,6 +340,7 @@ Sānu platums Izslēgtās kategorijas Lokālais avots + Saglabāt lappuses atsevišķās mapēs Iepriekšējais Noklusējuma lasīšanas režīms Kindle-ish @@ -375,6 +376,7 @@ Navigācija Invertēt skaļuma regulēšanas taustiņus Rādīt darbīūbas ar ilgu pieskārienu + Izveido mapes atbilstoši ieraksta nosaukumam Fona krāsa Mēroga tips Ietilpt ekrānā diff --git a/i18n/src/main/res/values-ms/strings.xml b/i18n/src/main/res/values-ms/strings.xml index 8fd5b4e82..f90cabf8a 100644 --- a/i18n/src/main/res/values-ms/strings.xml +++ b/i18n/src/main/res/values-ms/strings.xml @@ -519,6 +519,8 @@ Landskap Potret Tindakan + Mencipta folder mengikut tajuk entri + Simpan muka surat ke folder berasingan Jenis putaran skrin Skala kelabu Nyahdaya mod inkognito diff --git a/i18n/src/main/res/values-nb-rNO/strings.xml b/i18n/src/main/res/values-nb-rNO/strings.xml index dd3899d55..038c4d66a 100644 --- a/i18n/src/main/res/values-nb-rNO/strings.xml +++ b/i18n/src/main/res/values-nb-rNO/strings.xml @@ -530,6 +530,8 @@ Liggende Stående Rotasjon + Oppretter mapper i henhold til oppføringenes tittel + Lagre sider i egne mapper Handlinger Helt svart Oppstartsveiledning diff --git a/i18n/src/main/res/values-ne/strings.xml b/i18n/src/main/res/values-ne/strings.xml index a7f888988..e6b8328e0 100644 --- a/i18n/src/main/res/values-ne/strings.xml +++ b/i18n/src/main/res/values-ne/strings.xml @@ -242,7 +242,9 @@ स्क्रिन डज / चम्किलो जलाउनु / अँध्यारो गर्नु + फरक फोल्डरमा पृष्ठहरू सेभ गर्नुहोस् स्क्रिन अन राख्नुहोस् + इन्ट्रीहरूको शीर्षक अनुसार फोल्डरहरू सिर्जना गर्दछ कुल इन्ट्रीहरू %d वर्ग diff --git a/i18n/src/main/res/values-nl/strings.xml b/i18n/src/main/res/values-nl/strings.xml index 55f28c819..bf05a08f2 100644 --- a/i18n/src/main/res/values-nl/strings.xml +++ b/i18n/src/main/res/values-nl/strings.xml @@ -532,6 +532,8 @@ Staand Oriëntatie Automatisch + Mappen aanmaken op basis van titel + Pagina\'s opslaan in aparte mappen Acties Grijstinten Alles annuleren voor deze serie diff --git a/i18n/src/main/res/values-pl/strings.xml b/i18n/src/main/res/values-pl/strings.xml index 1e2c3ab5e..84c62b5f5 100644 --- a/i18n/src/main/res/values-pl/strings.xml +++ b/i18n/src/main/res/values-pl/strings.xml @@ -557,6 +557,8 @@ Nieprzeczytane Orientacja ekranu Automatycznie + Utwórz foldery względem tytułu + Zapisz strony do osobnych folderów Akcje Odcienie szarości Anuluj wszystko dla tego tytułu diff --git a/i18n/src/main/res/values-pt-rBR/strings.xml b/i18n/src/main/res/values-pt-rBR/strings.xml index 7005476ed..dc62600a4 100644 --- a/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/i18n/src/main/res/values-pt-rBR/strings.xml @@ -540,6 +540,8 @@ Erro ao copiar para a área de transferência Paisagem Retrato + Cria as pastas usando os títulos dos itens + Salvar as páginas em pastas separadas Ações Orientação Nível de cinza diff --git a/i18n/src/main/res/values-pt/strings.xml b/i18n/src/main/res/values-pt/strings.xml index c6ba00a29..421f7a455 100644 --- a/i18n/src/main/res/values-pt/strings.xml +++ b/i18n/src/main/res/values-pt/strings.xml @@ -571,6 +571,8 @@ Horizontal Vertical Tipo de rotação + Cria as pastas usando os títulos dos itens + Guarda páginas em pastas separadas Ações Tons de cinzento Data diff --git a/i18n/src/main/res/values-ro/strings.xml b/i18n/src/main/res/values-ro/strings.xml index d44b6cd06..289ac59f0 100644 --- a/i18n/src/main/res/values-ro/strings.xml +++ b/i18n/src/main/res/values-ro/strings.xml @@ -649,6 +649,7 @@ Acum %1$d zile Acum %1$d zile + Creează dosare în funcție de titlul intrărilor Automat Pornit @@ -662,6 +663,7 @@ Deactivat Șterge tot Acțiuni + Salvează pagini în dosare separate Fără descriere Dezactivează modul incognito Funcționează numai dacă capitolul curent + următorul sunt deja descărcate. diff --git a/i18n/src/main/res/values-ru/strings.xml b/i18n/src/main/res/values-ru/strings.xml index d1208de33..ca1b8495f 100644 --- a/i18n/src/main/res/values-ru/strings.xml +++ b/i18n/src/main/res/values-ru/strings.xml @@ -551,6 +551,8 @@ Не удалось скопировать в буфер обмена Альбомная Портретная + Создавать папки в соответствии с названием серии + Сохранять страницы в отдельные папки Действия Ориентация Оттенки серого diff --git a/i18n/src/main/res/values-sa/strings.xml b/i18n/src/main/res/values-sa/strings.xml index 04a955d27..115d2bdfe 100644 --- a/i18n/src/main/res/values-sa/strings.xml +++ b/i18n/src/main/res/values-sa/strings.xml @@ -253,6 +253,7 @@ ऊर्ध्वम् कार्याणि दीर्घस्पर्शने दर्शयतु + पुटानि भिन्नसञ्चयेषु रक्षतु पृष्ठभूमिवर्णः श्वेतः धूसरः @@ -277,6 +278,7 @@ पठितम् इति चिह्नितान् अध्यायान् लङ्घयतु प्रकाशयति द्वयम् + माङ्गाशीर्षकम् अनुसृत्य सञ्चयान् स्रक्ष्यति पृष्ठीकृतम् विस्तारणम् विस्तृतिं समुचितं कुरु diff --git a/i18n/src/main/res/values-sc/strings.xml b/i18n/src/main/res/values-sc/strings.xml index bcfe5ef2c..8480f152d 100644 --- a/i18n/src/main/res/values-sc/strings.xml +++ b/i18n/src/main/res/values-sc/strings.xml @@ -530,6 +530,8 @@ Orizontale Verticale Rotatzione + Creat cartellas in base a su tìtulu de sos elementos + Sarva sas pàginas in cartellas separadas Atziones Iscala de murros Disabìlita sa modalidade anònima diff --git a/i18n/src/main/res/values-sdh/strings.xml b/i18n/src/main/res/values-sdh/strings.xml index 23fdc7a4b..bda3063c9 100644 --- a/i18n/src/main/res/values-sdh/strings.xml +++ b/i18n/src/main/res/values-sdh/strings.xml @@ -175,6 +175,7 @@ ستوونی هەردووکیان کردارەکان + خەزێنە کردنی لاپەڕەکان لە فۆڵدەری جیاوزدا سپی خۆڵەمێشی پلە پلە پێچەوانەکراو @@ -212,6 +213,7 @@ دەوروبەری لاپەڕە گونجاو بە شاشە ئازاد + درووستکردنی فۆڵدەر بە پێی تایتڵی مانگا ڕەنگی باکگراوند سووچ ڕاست و چەپ diff --git a/i18n/src/main/res/values-sk/strings.xml b/i18n/src/main/res/values-sk/strings.xml index 6eb94a300..106836826 100644 --- a/i18n/src/main/res/values-sk/strings.xml +++ b/i18n/src/main/res/values-sk/strings.xml @@ -504,6 +504,7 @@ Odstrániť kategóriu Žiadne Zahrnúť: %s + Vytvára priečinky podľa názvu mangy Okraj Vpravo a vľavo Vľavo @@ -566,6 +567,7 @@ Nepodarilo sa získať zoznam rozšírení Inštaluje sa rozšírenie… Invertovať oblasti dotyku + Uloženie stránok do samostatných priečinkov Šedivá Na šírku Obnovenie už prebieha diff --git a/i18n/src/main/res/values-sq/strings.xml b/i18n/src/main/res/values-sq/strings.xml index 0b7da30c8..e8578d477 100644 --- a/i18n/src/main/res/values-sq/strings.xml +++ b/i18n/src/main/res/values-sq/strings.xml @@ -319,6 +319,7 @@ Instaloni dhe filloni Shizuku për të përdorur Shizuku si instalues shtesë. Animoni tranzicionet e faqeve Trego shkurtimisht modalitetin aktual kur hapet lexuesi + Ruani faqet në dosje të veçanta Ngjyra e sfondit E bardhë Gri @@ -371,6 +372,7 @@ %d kapitujt e ardhshëm të palexuar Nuk ka kapitull tjetër + Krijon dosje sipas titullit të hyrjeve E zezë Modaliteti i parazgjedhur i leximit Në formë L diff --git a/i18n/src/main/res/values-sr/strings.xml b/i18n/src/main/res/values-sr/strings.xml index 1772e56a0..075ce92ec 100644 --- a/i18n/src/main/res/values-sr/strings.xml +++ b/i18n/src/main/res/values-sr/strings.xml @@ -589,6 +589,8 @@ Вертикално Оба Радње + Сачувај странице у засебне фолдере + Прави датотеке по имену наслова У облику слова L Оријентација Усправно diff --git a/i18n/src/main/res/values-sv/strings.xml b/i18n/src/main/res/values-sv/strings.xml index aad384aeb..1f926ba49 100644 --- a/i18n/src/main/res/values-sv/strings.xml +++ b/i18n/src/main/res/values-sv/strings.xml @@ -530,6 +530,8 @@ Liggande Porträtt Rotation + Skapa mappar enligt posternas titel + Spara sidor i separata mappar Åtgärder Gråskala Automatisk diff --git a/i18n/src/main/res/values-th/strings.xml b/i18n/src/main/res/values-th/strings.xml index 55d05b2ca..f3d2e6e89 100644 --- a/i18n/src/main/res/values-th/strings.xml +++ b/i18n/src/main/res/values-th/strings.xml @@ -301,6 +301,8 @@ รูปตัว L อัตโนมัติ เทา + สร้างโฟลเดอร์ตามชื่อเรื่อง + บันทึกหน้าลงในโฟลเดอร์ที่แยกต่างหาก การกระทำ ทั้งสอง แนวตั้ง diff --git a/i18n/src/main/res/values-tr/strings.xml b/i18n/src/main/res/values-tr/strings.xml index 5980655f8..0fc6713e0 100644 --- a/i18n/src/main/res/values-tr/strings.xml +++ b/i18n/src/main/res/values-tr/strings.xml @@ -530,6 +530,8 @@ Yatay Dikey Döndürme + Girdilerin başlığına göre sıralaç oluşturur + Sayfaları ayrı sıralaçlara kaydet Eylemler Boz tonlama Gizli kipi devre dışı bırak diff --git a/i18n/src/main/res/values-uk/strings.xml b/i18n/src/main/res/values-uk/strings.xml index 53fbdbb7e..ea3386d7d 100644 --- a/i18n/src/main/res/values-uk/strings.xml +++ b/i18n/src/main/res/values-uk/strings.xml @@ -551,6 +551,8 @@ Альбомна Портретна Орієнтація + Створювати теки в відповідності до назви записів + Зберігати сторінки до окремих тек Дії Відтінки сірого Вимкнути режим інкогніто diff --git a/i18n/src/main/res/values-uz/strings.xml b/i18n/src/main/res/values-uz/strings.xml index 1646c2213..19729811c 100644 --- a/i18n/src/main/res/values-uz/strings.xml +++ b/i18n/src/main/res/values-uz/strings.xml @@ -291,6 +291,7 @@ Uskuna uchun avtomatik yangilanishlarni cheklash Takrorlanuvchi boblarni o\'tkazib yuborish + Sahifalarni alohida papkalarga saqlash Gorizontal Vertikal Ikkala taraf @@ -313,6 +314,7 @@ Sahifabay Oq Yo\'q + Qism nomiga asoslanib papka yaratish Keyingi Chapdan o\'ngga Ovoz tugmalari diff --git a/i18n/src/main/res/values-vi/strings.xml b/i18n/src/main/res/values-vi/strings.xml index 8d4a5e925..23f49b3c8 100644 --- a/i18n/src/main/res/values-vi/strings.xml +++ b/i18n/src/main/res/values-vi/strings.xml @@ -531,6 +531,8 @@ Phải và trái Tự động Xám + Tạo thư mục dựa theo tên truyện + Lưu lại trang trong thư mục riêng Hành động Cả hai Dọc diff --git a/i18n/src/main/res/values-zh-rCN/strings.xml b/i18n/src/main/res/values-zh-rCN/strings.xml index 51d3299dd..72c351e4c 100644 --- a/i18n/src/main/res/values-zh-rCN/strings.xml +++ b/i18n/src/main/res/values-zh-rCN/strings.xml @@ -518,6 +518,8 @@ 无法复制到剪贴板 横屏 竖屏 + 根据作品标题创建文件夹 + 将图片保存到单独文件夹 操作菜单 屏幕方向 灰度 diff --git a/i18n/src/main/res/values-zh-rTW/strings.xml b/i18n/src/main/res/values-zh-rTW/strings.xml index b01e748b2..8a26a92e7 100644 --- a/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/i18n/src/main/res/values-zh-rTW/strings.xml @@ -517,6 +517,8 @@ \n \n隨後請安裝所有遺失的擴充套件並重新登入各歷程平台。 類別同時屬於「排除」及「包含」的作品,將不會自動下載。 + 儲存頁面至個別資料夾 + 根據作品標題建立資料夾 開始閱讀時,短暫浮現輕觸區域 輕觸區域提示 類別同時屬於「排除」及「包含」的作品,將不會自動更新。 diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index ef8354abc..e7bf21e34 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -367,6 +367,8 @@ Both Actions Show actions on long tap + Save pages into separate folders + Creates folders according to entries\' title Background color White Gray From 69223df27c198550a7c43dc1af4c65f85bcb395b Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 4 Nov 2023 17:05:38 -0400 Subject: [PATCH 43/66] Move tracker binding logic to interactor --- .../java/eu/kanade/domain/DomainModule.kt | 2 +- .../domain/track/interactor/AddTracks.kt | 97 +++++++++++++++---- .../tachiyomi/data/track/BaseTracker.kt | 82 +++------------- .../source/browse/BrowseSourceScreenModel.kt | 2 +- .../tachiyomi/ui/manga/MangaScreenModel.kt | 2 +- 5 files changed, 97 insertions(+), 88 deletions(-) diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 9967e000f..49c130852 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -118,7 +118,7 @@ class DomainModule : InjektModule { addSingletonFactory { TrackRepositoryImpl(get()) } addFactory { TrackChapter(get(), get(), get(), get()) } - addFactory { AddTracks(get(), get(), get()) } + addFactory { AddTracks(get(), get(), get(), get()) } addFactory { RefreshTracks(get(), get(), get(), get()) } addFactory { DeleteTrack(get()) } addFactory { GetTracksPerManga(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 index 45340e44a..885a6249f 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 @@ -1,45 +1,104 @@ package eu.kanade.domain.track.interactor +import eu.kanade.domain.track.model.toDbTrack import eu.kanade.domain.track.model.toDomainTrack +import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.EnhancedTracker import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone import logcat.LogPriority +import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withNonCancellableContext import tachiyomi.core.util.system.logcat +import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId +import tachiyomi.domain.history.interactor.GetHistory import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.InsertTrack +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import java.time.ZoneOffset class AddTracks( private val getTracks: GetTracks, private val insertTrack: InsertTrack, private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack, + private val getChaptersByMangaId: GetChaptersByMangaId, ) { - 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()!!) + // TODO: update all trackers based on common data + suspend fun bind(tracker: Tracker, item: Track, mangaId: Long) = withNonCancellableContext { + withIOContext { + val allChapters = getChaptersByMangaId.await(mangaId) + val hasReadChapters = allChapters.any { it.read } + tracker.bind(item, hasReadChapters) - syncChapterProgressWithTrack.await( - manga.id, - track.toDomainTrack()!!, - service, + var track = item.toDomainTrack(idRequired = false) ?: return@withIOContext + + insertTrack.await(track) + + // TODO: merge into [SyncChapterProgressWithTrack]? + // Update chapter progress if newer chapters marked read locally + if (hasReadChapters) { + val latestLocalReadChapterNumber = allChapters + .sortedBy { it.chapterNumber } + .takeWhile { it.read } + .lastOrNull() + ?.chapterNumber ?: -1.0 + + if (latestLocalReadChapterNumber > track.lastChapterRead) { + track = track.copy( + lastChapterRead = latestLocalReadChapterNumber, + ) + tracker.setRemoteLastChapterRead(track.toDbTrack(), latestLocalReadChapterNumber.toInt()) + } + + if (track.startDate <= 0) { + val firstReadChapterDate = Injekt.get().await(mangaId) + .sortedBy { it.readAt } + .firstOrNull() + ?.readAt + + firstReadChapterDate?.let { + val startDate = firstReadChapterDate.time.convertEpochMillisZone(ZoneOffset.systemDefault(), ZoneOffset.UTC) + track = track.copy( + startDate = startDate, ) + tracker.setRemoteStartDate(track.toDbTrack(), startDate) } - } catch (e: Exception) { - logcat( - LogPriority.WARN, - e, - ) { "Could not match manga: ${manga.title} with service $service" } } } + + syncChapterProgressWithTrack.await(mangaId, track, tracker) + } + } + + suspend fun bindEnhancedTrackers(manga: Manga, source: Source) = withNonCancellableContext { + withIOContext { + 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/tachiyomi/data/track/BaseTracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt index 94b81783d..277638bc1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt @@ -2,26 +2,21 @@ package eu.kanade.tachiyomi.data.track import android.app.Application import androidx.annotation.CallSuper -import eu.kanade.domain.track.interactor.SyncChapterProgressWithTrack -import eu.kanade.domain.track.model.toDbTrack +import eu.kanade.domain.track.interactor.AddTracks import eu.kanade.domain.track.model.toDomainTrack import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.network.NetworkHelper -import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone import eu.kanade.tachiyomi.util.system.toast import logcat.LogPriority import okhttp3.OkHttpClient import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.system.logcat -import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId -import tachiyomi.domain.history.interactor.GetHistory import tachiyomi.domain.track.interactor.InsertTrack import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy -import java.time.ZoneOffset import tachiyomi.domain.track.model.Track as DomainTrack abstract class BaseTracker( @@ -31,8 +26,8 @@ abstract class BaseTracker( val trackPreferences: TrackPreferences by injectLazy() val networkService: NetworkHelper by injectLazy() + private val addTracks: AddTracks by injectLazy() private val insertTrack: InsertTrack by injectLazy() - private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack by injectLazy() override val client: OkHttpClient get() = networkService.client @@ -66,53 +61,10 @@ abstract class BaseTracker( trackPreferences.setCredentials(this, username, password) } - // TODO: move this to an interactor, and update all trackers based on common data override suspend fun register(item: Track, mangaId: Long) { item.manga_id = mangaId try { - withIOContext { - val allChapters = Injekt.get().await(mangaId) - val hasReadChapters = allChapters.any { it.read } - bind(item, hasReadChapters) - - var track = item.toDomainTrack(idRequired = false) ?: return@withIOContext - - insertTrack.await(track) - - // TODO: merge into [SyncChapterProgressWithTrack]? - // Update chapter progress if newer chapters marked read locally - if (hasReadChapters) { - val latestLocalReadChapterNumber = allChapters - .sortedBy { it.chapterNumber } - .takeWhile { it.read } - .lastOrNull() - ?.chapterNumber ?: -1.0 - - if (latestLocalReadChapterNumber > track.lastChapterRead) { - track = track.copy( - lastChapterRead = latestLocalReadChapterNumber, - ) - setRemoteLastChapterRead(track.toDbTrack(), latestLocalReadChapterNumber.toInt()) - } - - if (track.startDate <= 0) { - val firstReadChapterDate = Injekt.get().await(mangaId) - .sortedBy { it.readAt } - .firstOrNull() - ?.readAt - - firstReadChapterDate?.let { - val startDate = firstReadChapterDate.time.convertEpochMillisZone(ZoneOffset.systemDefault(), ZoneOffset.UTC) - track = track.copy( - startDate = startDate, - ) - setRemoteStartDate(track.toDbTrack(), startDate) - } - } - } - - syncChapterProgressWithTrack.await(mangaId, track, this@BaseTracker) - } + addTracks.bind(this, item, mangaId) } catch (e: Throwable) { withUIContext { Injekt.get().toast(e.message) } } @@ -123,7 +75,7 @@ abstract class BaseTracker( if (track.status == getCompletionStatus() && track.total_chapters != 0) { track.last_chapter_read = track.total_chapters.toFloat() } - withIOContext { updateRemote(track) } + updateRemote(track) } override suspend fun setRemoteLastChapterRead(track: Track, chapterNumber: Int) { @@ -135,35 +87,33 @@ abstract class BaseTracker( track.status = getCompletionStatus() track.finished_reading_date = System.currentTimeMillis() } - withIOContext { updateRemote(track) } + updateRemote(track) } override suspend fun setRemoteScore(track: Track, scoreString: String) { track.score = indexToScore(getScoreList().indexOf(scoreString)) - withIOContext { updateRemote(track) } + updateRemote(track) } override suspend fun setRemoteStartDate(track: Track, epochMillis: Long) { track.started_reading_date = epochMillis - withIOContext { updateRemote(track) } + updateRemote(track) } override suspend fun setRemoteFinishDate(track: Track, epochMillis: Long) { track.finished_reading_date = epochMillis - withIOContext { updateRemote(track) } + updateRemote(track) } - private suspend fun updateRemote(track: Track) { - withIOContext { - try { - update(track) - track.toDomainTrack(idRequired = false)?.let { - insertTrack.await(it) - } - } catch (e: Exception) { - logcat(LogPriority.ERROR, e) { "Failed to update remote track data id=$id" } - withUIContext { Injekt.get().toast(e.message) } + private suspend fun updateRemote(track: Track): Unit = withIOContext { + try { + update(track) + track.toDomainTrack(idRequired = false)?.let { + insertTrack.await(it) } + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) { "Failed to update remote track data id=$id" } + withUIContext { Injekt.get().toast(e.message) } } } } 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 2abd5e0ac..37203015a 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 @@ -233,7 +233,7 @@ class BrowseSourceScreenModel( new = new.removeCovers(coverCache) } else { setMangaDefaultChapterFlags.await(manga) - addTracks.bindEnhancedTracks(manga, source) + addTracks.bindEnhancedTrackers(manga, source) } updateManga.await(new.toMangaUpdate()) 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 4fa4baba5..37c4dab9b 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 @@ -319,7 +319,7 @@ class MangaScreenModel( } // Finally match with enhanced tracking when available - addTracks.bindEnhancedTracks(manga, state.source) + addTracks.bindEnhancedTrackers(manga, state.source) } } } From 4146c4c31d069ce9fb7ab36d72f1f8fa2be1e050 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 4 Nov 2023 17:50:33 -0400 Subject: [PATCH 44/66] Ensure page indicator texts are centered Maybe fixes #9976 --- .../presentation/reader/PageIndicatorText.kt | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) 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 69df2a727..470a731c8 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/PageIndicatorText.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/PageIndicatorText.kt @@ -4,11 +4,14 @@ import androidx.compose.foundation.layout.Box import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp +import eu.kanade.presentation.theme.TachiyomiTheme +import tachiyomi.presentation.core.util.ThemePreviews @Composable fun PageIndicatorText( @@ -19,24 +22,35 @@ fun PageIndicatorText( val text = "$currentPage / $totalPages" - Box { - Text( - text = text, - color = Color(45, 45, 45), - fontSize = MaterialTheme.typography.bodySmall.fontSize, - fontWeight = FontWeight.Bold, - letterSpacing = 1.sp, - style = TextStyle.Default.copy( - drawStyle = Stroke(width = 4f), - ), - ) + val style = TextStyle( + color = Color(235, 235, 235), + fontSize = MaterialTheme.typography.bodySmall.fontSize, + fontWeight = FontWeight.Bold, + letterSpacing = 1.sp, + ) + val strokeStyle = style.copy( + color = Color(45, 45, 45), + drawStyle = Stroke(width = 4f), + ) + Box( + contentAlignment = Alignment.Center, + ) { Text( text = text, - color = Color(235, 235, 235), - fontSize = MaterialTheme.typography.bodySmall.fontSize, - fontWeight = FontWeight.Bold, - letterSpacing = 1.sp, + style = strokeStyle, + ) + Text( + text = text, + style = style, ) } } + +@ThemePreviews +@Composable +private fun PageIndicatorTextPreview() { + TachiyomiTheme { + PageIndicatorText(currentPage = 10, totalPages = 69) + } +} From 64c50c1283969dbc16c519f87cad3b5c9001b4cb Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 4 Nov 2023 19:20:48 -0400 Subject: [PATCH 45/66] Require Android 8+ Given that the next stable version of Chrome (120) will require Android 8+, it's inevitable that the WebView functionality will gradually break. As always, newer OS versions are recommended for better support with evolving Internet technologies. According to https://apilevels.com/, Android 8+ still covers 93.7% of Android users. --- .../java/eu/kanade/domain/ui/UiPreferences.kt | 6 +- .../manga/components/MangaCoverDialog.kt | 8 +- .../settings/screen/SettingsAdvancedScreen.kt | 101 ++++++++---------- .../screen/SettingsAppearanceScreen.kt | 18 +--- .../settings/screen/SettingsReaderScreen.kt | 1 - .../eu/kanade/presentation/util/Navigator.kt | 1 + app/src/main/java/eu/kanade/tachiyomi/App.kt | 27 +++-- .../data/coil/TachiyomiImageDecoder.kt | 4 +- .../data/notification/NotificationReceiver.kt | 23 ++-- .../extension/installer/ShizukuInstaller.kt | 7 +- .../tachiyomi/util/storage/FileExtensions.kt | 8 +- .../util/system/NetworkExtensions.kt | 3 +- buildSrc/src/main/kotlin/AndroidConfig.kt | 2 +- .../util/system/WebViewClientCompat.kt | 3 - .../tachiyomi/util/system/WebViewUtil.kt | 15 +-- 15 files changed, 84 insertions(+), 143 deletions(-) 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 294812bdc..efb27fa02 100644 --- a/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt +++ b/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt @@ -1,6 +1,5 @@ package eu.kanade.domain.ui -import android.os.Build import eu.kanade.domain.ui.model.AppTheme import eu.kanade.domain.ui.model.TabletUiMode import eu.kanade.domain.ui.model.ThemeMode @@ -16,10 +15,7 @@ class UiPreferences( private val preferenceStore: PreferenceStore, ) { - fun themeMode() = preferenceStore.getEnum( - "pref_theme_mode_key", - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ThemeMode.SYSTEM } else { ThemeMode.LIGHT }, - ) + fun themeMode() = preferenceStore.getEnum("pref_theme_mode_key", ThemeMode.SYSTEM) fun appTheme() = preferenceStore.getEnum( "pref_app_theme", diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt index 43e9ac158..21057a634 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt @@ -2,7 +2,6 @@ package eu.kanade.presentation.manga.components import android.graphics.Bitmap import android.graphics.drawable.BitmapDrawable -import android.os.Build import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -176,14 +175,9 @@ fun MangaCoverDialog( // Copy bitmap in case it came from memory cache // Because SSIV needs to thoroughly read the image val copy = (drawable as? BitmapDrawable)?.let { - val config = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - Bitmap.Config.HARDWARE - } else { - Bitmap.Config.ARGB_8888 - } BitmapDrawable( view.context.resources, - it.bitmap.copy(config, false), + it.bitmap.copy(Bitmap.Config.HARDWARE, false), ) } ?: drawable view.setImage(copy, ReaderPageImageView.Config(zoomDuration = 500)) 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 97d852e50..6b8cc1454 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 @@ -3,7 +3,6 @@ package eu.kanade.presentation.more.settings.screen import android.annotation.SuppressLint import android.content.ActivityNotFoundException import android.content.Intent -import android.os.Build import android.provider.Settings import android.webkit.WebStorage import android.webkit.WebView @@ -81,62 +80,50 @@ object SettingsAdvancedScreen : SearchableSettings { val basePreferences = remember { Injekt.get() } val networkPreferences = remember { Injekt.get() } - return buildList { - addAll( - listOf( - Preference.PreferenceItem.SwitchPreference( - pref = basePreferences.acraEnabled(), - title = stringResource(R.string.pref_enable_acra), - subtitle = stringResource(R.string.pref_acra_summary), - enabled = isPreviewBuildType || isReleaseBuildType, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_dump_crash_logs), - subtitle = stringResource(R.string.pref_dump_crash_logs_summary), - onClick = { - scope.launch { - CrashLogUtil(context).dumpLogs() - } - }, - ), - Preference.PreferenceItem.SwitchPreference( - pref = networkPreferences.verboseLogging(), - title = stringResource(R.string.pref_verbose_logging), - subtitle = stringResource(R.string.pref_verbose_logging_summary), - onValueChanged = { - context.toast(R.string.requires_app_restart) - true - }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_debug_info), - onClick = { navigator.push(DebugInfoScreen()) }, - ), - ), - ) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - add( - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_manage_notifications), - onClick = { - val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { - putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) - } - context.startActivity(intent) - }, - ), - ) - } - addAll( - listOf( - getBackgroundActivityGroup(), - getDataGroup(), - getNetworkGroup(networkPreferences = networkPreferences), - getLibraryGroup(), - getExtensionsGroup(basePreferences = basePreferences), - ), - ) - } + return listOf( + Preference.PreferenceItem.SwitchPreference( + pref = basePreferences.acraEnabled(), + title = stringResource(R.string.pref_enable_acra), + subtitle = stringResource(R.string.pref_acra_summary), + enabled = isPreviewBuildType || isReleaseBuildType, + ), + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_dump_crash_logs), + subtitle = stringResource(R.string.pref_dump_crash_logs_summary), + onClick = { + scope.launch { + CrashLogUtil(context).dumpLogs() + } + }, + ), + Preference.PreferenceItem.SwitchPreference( + pref = networkPreferences.verboseLogging(), + title = stringResource(R.string.pref_verbose_logging), + subtitle = stringResource(R.string.pref_verbose_logging_summary), + onValueChanged = { + context.toast(R.string.requires_app_restart) + true + }, + ), + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_debug_info), + onClick = { navigator.push(DebugInfoScreen()) }, + ), + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_manage_notifications), + onClick = { + val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { + putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) + } + context.startActivity(intent) + }, + ), + getBackgroundActivityGroup(), + getDataGroup(), + getNetworkGroup(networkPreferences = networkPreferences), + getLibraryGroup(), + getExtensionsGroup(basePreferences = basePreferences), + ) } @Composable 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 4540aee95..0ee26274f 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 @@ -2,7 +2,6 @@ package eu.kanade.presentation.more.settings.screen import android.app.Activity import android.content.Context -import android.os.Build import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatDelegate import androidx.compose.runtime.Composable @@ -81,18 +80,11 @@ object SettingsAppearanceScreen : SearchableSettings { Preference.PreferenceItem.ListPreference( pref = themeModePref, title = stringResource(R.string.pref_theme_mode), - entries = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - mapOf( - ThemeMode.SYSTEM to stringResource(R.string.theme_system), - ThemeMode.LIGHT to stringResource(R.string.theme_light), - ThemeMode.DARK to stringResource(R.string.theme_dark), - ) - } else { - mapOf( - ThemeMode.LIGHT to stringResource(R.string.theme_light), - ThemeMode.DARK to stringResource(R.string.theme_dark), - ) - }, + entries = mapOf( + ThemeMode.SYSTEM to stringResource(R.string.theme_system), + ThemeMode.LIGHT to stringResource(R.string.theme_light), + ThemeMode.DARK to stringResource(R.string.theme_dark), + ), ), Preference.PreferenceItem.CustomPreference( title = stringResource(R.string.pref_app_theme), 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 14e0fd9df..0f343aa3d 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 @@ -58,7 +58,6 @@ object SettingsReaderScreen : SearchableSettings { pref = readerPref.trueColor(), title = stringResource(R.string.pref_true_color), subtitle = stringResource(R.string.pref_true_color_summary), - enabled = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O, ), Preference.PreferenceItem.SwitchPreference( pref = readerPref.pageTransitions(), diff --git a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt index bcbf7110f..6b5fceda7 100644 --- a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt +++ b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt @@ -79,6 +79,7 @@ fun ScreenTransition( targetState = navigator.lastItem, transitionSpec = transition, modifier = modifier, + label = "ScreenTransition", ) { screen -> navigator.saveableState("transition", screen) { content(screen) diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 822c66b81..4323200dd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -171,22 +171,19 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { } override fun getPackageName(): String { - // This causes freezes in Android 6/7 for some reason - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - try { - // Override the value passed as X-Requested-With in WebView requests - val stackTrace = Looper.getMainLooper().thread.stackTrace - val chromiumElement = stackTrace.find { - it.className.equals( - "org.chromium.base.BuildInfo", - ignoreCase = true, - ) - } - if (chromiumElement?.methodName.equals("getAll", ignoreCase = true)) { - return WebViewUtil.SPOOF_PACKAGE_NAME - } - } catch (e: Exception) { + try { + // Override the value passed as X-Requested-With in WebView requests + val stackTrace = Looper.getMainLooper().thread.stackTrace + val chromiumElement = stackTrace.find { + it.className.equals( + "org.chromium.base.BuildInfo", + ignoreCase = true, + ) } + if (chromiumElement?.methodName.equals("getAll", ignoreCase = true)) { + return WebViewUtil.SPOOF_PACKAGE_NAME + } + } catch (e: Exception) { } return super.getPackageName() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt b/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt index e0a5ffe8e..fb1278614 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt @@ -1,6 +1,5 @@ package eu.kanade.tachiyomi.data.coil -import android.os.Build import androidx.core.graphics.drawable.toDrawable import coil.ImageLoader import coil.decode.DecodeResult @@ -48,8 +47,7 @@ class TachiyomiImageDecoder(private val resources: ImageSource, private val opti ImageUtil.findImageType(it) } return when (type) { - ImageUtil.ImageType.AVIF, ImageUtil.ImageType.JXL -> true - ImageUtil.ImageType.HEIF -> Build.VERSION.SDK_INT < Build.VERSION_CODES.O + ImageUtil.ImageType.AVIF, ImageUtil.ImageType.JXL, ImageUtil.ImageType.HEIF -> true else -> false } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index 566da8e9c..22c19cab0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -5,7 +5,6 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.net.Uri -import android.os.Build import androidx.core.net.toUri import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.BackupRestoreJob @@ -368,20 +367,18 @@ class NotificationReceiver : BroadcastReceiver() { When programmatically dismissing this notification, the group notification is not automatically dismissed. */ - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - val groupKey = context.notificationManager.activeNotifications.find { - it.id == notificationId - }?.groupKey + val groupKey = context.notificationManager.activeNotifications.find { + it.id == notificationId + }?.groupKey - if (groupId != null && groupId != 0 && groupKey != null && groupKey.isNotEmpty()) { - val notifications = context.notificationManager.activeNotifications.filter { - it.groupKey == groupKey - } + if (groupId != null && groupId != 0 && !groupKey.isNullOrEmpty()) { + val notifications = context.notificationManager.activeNotifications.filter { + it.groupKey == groupKey + } - if (notifications.size == 2) { - context.cancelNotification(groupId) - return - } + if (notifications.size == 2) { + context.cancelNotification(groupId) + return } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt index 6cc4efd33..0d785e3a6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt @@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.installer import android.app.Service import android.content.pm.PackageManager -import android.os.Build import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.extension.model.InstallStep import eu.kanade.tachiyomi.util.system.getUriSize @@ -50,11 +49,7 @@ class ShizukuInstaller(private val service: Service) : Installer(service) { try { val size = service.getUriSize(entry.uri) ?: throw IllegalStateException() service.contentResolver.openInputStream(entry.uri)!!.use { - val createCommand = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - "pm install-create --user current -r -i ${service.packageName} -S $size" - } else { - "pm install-create -r -i ${service.packageName} -S $size" - } + val createCommand = "pm install-create --user current -r -i ${service.packageName} -S $size" val createResult = exec(createCommand) sessionId = SESSION_ID_REGEX.find(createResult.out)?.value ?: throw RuntimeException("Failed to create install session") diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt index 94a65ddcd..f86d36485 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt @@ -2,9 +2,7 @@ package eu.kanade.tachiyomi.util.storage import android.content.Context import android.net.Uri -import android.os.Build import androidx.core.content.FileProvider -import androidx.core.net.toUri import eu.kanade.tachiyomi.BuildConfig import java.io.File @@ -17,11 +15,7 @@ val Context.cacheImageDir: File * @param context context of application */ fun File.getUriCompat(context: Context): Uri { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", this) - } else { - this.toUri() - } + return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", this) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt index 8d72a9c86..18e16baac 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt @@ -18,8 +18,7 @@ fun Context.isOnline(): Boolean { val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false val maxTransport = when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 -> NetworkCapabilities.TRANSPORT_LOWPAN - Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> NetworkCapabilities.TRANSPORT_WIFI_AWARE - else -> NetworkCapabilities.TRANSPORT_VPN + else -> NetworkCapabilities.TRANSPORT_WIFI_AWARE } return (NetworkCapabilities.TRANSPORT_CELLULAR..maxTransport).any(networkCapabilities::hasTransport) } diff --git a/buildSrc/src/main/kotlin/AndroidConfig.kt b/buildSrc/src/main/kotlin/AndroidConfig.kt index f63c07729..9a5cc2f6b 100644 --- a/buildSrc/src/main/kotlin/AndroidConfig.kt +++ b/buildSrc/src/main/kotlin/AndroidConfig.kt @@ -1,6 +1,6 @@ object AndroidConfig { const val compileSdk = 34 - const val minSdk = 23 + const val minSdk = 26 const val targetSdk = 29 const val ndk = "22.1.7171670" } 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 93ce0337d..6547a46e0 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 @@ -1,7 +1,5 @@ package eu.kanade.tachiyomi.util.system -import android.annotation.TargetApi -import android.os.Build import android.webkit.WebResourceError import android.webkit.WebResourceRequest import android.webkit.WebResourceResponse @@ -28,7 +26,6 @@ abstract class WebViewClientCompat : WebViewClient() { ) { } - @TargetApi(Build.VERSION_CODES.N) final override fun shouldOverrideUrlLoading( view: WebView, request: WebResourceRequest, 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 b3329e9b7..b60bc8dc0 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 @@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.util.system import android.annotation.SuppressLint import android.content.Context import android.content.pm.PackageManager -import android.os.Build import android.webkit.CookieManager import android.webkit.WebSettings import android.webkit.WebView @@ -35,15 +34,11 @@ object WebViewUtil { } fun getVersion(context: Context): String { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val webView = WebView.getCurrentWebViewPackage() ?: return "how did you get here?" - val pm = context.packageManager - val label = webView.applicationInfo.loadLabel(pm) - val version = webView.versionName - "$label $version" - } else { - "Unknown" - } + val webView = WebView.getCurrentWebViewPackage() ?: return "how did you get here?" + val pm = context.packageManager + val label = webView.applicationInfo.loadLabel(pm) + val version = webView.versionName + return "$label $version" } fun supportsWebView(context: Context): Boolean { From c5e8c9f01fa6b54425675ee3ebdc6f735aee7ba9 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 4 Nov 2023 19:36:25 -0400 Subject: [PATCH 46/66] Revert "Require Android 8+" This reverts commit 64c50c1283969dbc16c519f87cad3b5c9001b4cb. Forgot we need to manage app update checks manually... --- .../java/eu/kanade/domain/ui/UiPreferences.kt | 6 +- .../manga/components/MangaCoverDialog.kt | 8 +- .../settings/screen/SettingsAdvancedScreen.kt | 101 ++++++++++-------- .../screen/SettingsAppearanceScreen.kt | 18 +++- .../settings/screen/SettingsReaderScreen.kt | 1 + .../eu/kanade/presentation/util/Navigator.kt | 1 - app/src/main/java/eu/kanade/tachiyomi/App.kt | 27 ++--- .../data/coil/TachiyomiImageDecoder.kt | 4 +- .../data/notification/NotificationReceiver.kt | 23 ++-- .../extension/installer/ShizukuInstaller.kt | 7 +- .../tachiyomi/util/storage/FileExtensions.kt | 8 +- .../util/system/NetworkExtensions.kt | 3 +- buildSrc/src/main/kotlin/AndroidConfig.kt | 2 +- .../util/system/WebViewClientCompat.kt | 3 + .../tachiyomi/util/system/WebViewUtil.kt | 15 ++- 15 files changed, 143 insertions(+), 84 deletions(-) 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 efb27fa02..294812bdc 100644 --- a/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt +++ b/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt @@ -1,5 +1,6 @@ package eu.kanade.domain.ui +import android.os.Build import eu.kanade.domain.ui.model.AppTheme import eu.kanade.domain.ui.model.TabletUiMode import eu.kanade.domain.ui.model.ThemeMode @@ -15,7 +16,10 @@ class UiPreferences( private val preferenceStore: PreferenceStore, ) { - fun themeMode() = preferenceStore.getEnum("pref_theme_mode_key", ThemeMode.SYSTEM) + fun themeMode() = preferenceStore.getEnum( + "pref_theme_mode_key", + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ThemeMode.SYSTEM } else { ThemeMode.LIGHT }, + ) fun appTheme() = preferenceStore.getEnum( "pref_app_theme", diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt index 21057a634..43e9ac158 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt @@ -2,6 +2,7 @@ package eu.kanade.presentation.manga.components import android.graphics.Bitmap import android.graphics.drawable.BitmapDrawable +import android.os.Build import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -175,9 +176,14 @@ fun MangaCoverDialog( // Copy bitmap in case it came from memory cache // Because SSIV needs to thoroughly read the image val copy = (drawable as? BitmapDrawable)?.let { + val config = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Bitmap.Config.HARDWARE + } else { + Bitmap.Config.ARGB_8888 + } BitmapDrawable( view.context.resources, - it.bitmap.copy(Bitmap.Config.HARDWARE, false), + it.bitmap.copy(config, false), ) } ?: drawable view.setImage(copy, ReaderPageImageView.Config(zoomDuration = 500)) 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 6b8cc1454..97d852e50 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 @@ -3,6 +3,7 @@ package eu.kanade.presentation.more.settings.screen import android.annotation.SuppressLint import android.content.ActivityNotFoundException import android.content.Intent +import android.os.Build import android.provider.Settings import android.webkit.WebStorage import android.webkit.WebView @@ -80,50 +81,62 @@ object SettingsAdvancedScreen : SearchableSettings { val basePreferences = remember { Injekt.get() } val networkPreferences = remember { Injekt.get() } - return listOf( - Preference.PreferenceItem.SwitchPreference( - pref = basePreferences.acraEnabled(), - title = stringResource(R.string.pref_enable_acra), - subtitle = stringResource(R.string.pref_acra_summary), - enabled = isPreviewBuildType || isReleaseBuildType, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_dump_crash_logs), - subtitle = stringResource(R.string.pref_dump_crash_logs_summary), - onClick = { - scope.launch { - CrashLogUtil(context).dumpLogs() - } - }, - ), - Preference.PreferenceItem.SwitchPreference( - pref = networkPreferences.verboseLogging(), - title = stringResource(R.string.pref_verbose_logging), - subtitle = stringResource(R.string.pref_verbose_logging_summary), - onValueChanged = { - context.toast(R.string.requires_app_restart) - true - }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_debug_info), - onClick = { navigator.push(DebugInfoScreen()) }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_manage_notifications), - onClick = { - val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { - putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) - } - context.startActivity(intent) - }, - ), - getBackgroundActivityGroup(), - getDataGroup(), - getNetworkGroup(networkPreferences = networkPreferences), - getLibraryGroup(), - getExtensionsGroup(basePreferences = basePreferences), - ) + return buildList { + addAll( + listOf( + Preference.PreferenceItem.SwitchPreference( + pref = basePreferences.acraEnabled(), + title = stringResource(R.string.pref_enable_acra), + subtitle = stringResource(R.string.pref_acra_summary), + enabled = isPreviewBuildType || isReleaseBuildType, + ), + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_dump_crash_logs), + subtitle = stringResource(R.string.pref_dump_crash_logs_summary), + onClick = { + scope.launch { + CrashLogUtil(context).dumpLogs() + } + }, + ), + Preference.PreferenceItem.SwitchPreference( + pref = networkPreferences.verboseLogging(), + title = stringResource(R.string.pref_verbose_logging), + subtitle = stringResource(R.string.pref_verbose_logging_summary), + onValueChanged = { + context.toast(R.string.requires_app_restart) + true + }, + ), + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_debug_info), + onClick = { navigator.push(DebugInfoScreen()) }, + ), + ), + ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + add( + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_manage_notifications), + onClick = { + val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { + putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) + } + context.startActivity(intent) + }, + ), + ) + } + addAll( + listOf( + getBackgroundActivityGroup(), + getDataGroup(), + getNetworkGroup(networkPreferences = networkPreferences), + getLibraryGroup(), + getExtensionsGroup(basePreferences = basePreferences), + ), + ) + } } @Composable 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 0ee26274f..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 @@ -2,6 +2,7 @@ package eu.kanade.presentation.more.settings.screen import android.app.Activity import android.content.Context +import android.os.Build import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatDelegate import androidx.compose.runtime.Composable @@ -80,11 +81,18 @@ object SettingsAppearanceScreen : SearchableSettings { Preference.PreferenceItem.ListPreference( pref = themeModePref, title = stringResource(R.string.pref_theme_mode), - entries = mapOf( - ThemeMode.SYSTEM to stringResource(R.string.theme_system), - ThemeMode.LIGHT to stringResource(R.string.theme_light), - ThemeMode.DARK to stringResource(R.string.theme_dark), - ), + entries = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mapOf( + ThemeMode.SYSTEM to stringResource(R.string.theme_system), + ThemeMode.LIGHT to stringResource(R.string.theme_light), + ThemeMode.DARK to stringResource(R.string.theme_dark), + ) + } else { + mapOf( + ThemeMode.LIGHT to stringResource(R.string.theme_light), + ThemeMode.DARK to stringResource(R.string.theme_dark), + ) + }, ), Preference.PreferenceItem.CustomPreference( title = stringResource(R.string.pref_app_theme), 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 0f343aa3d..14e0fd9df 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 @@ -58,6 +58,7 @@ object SettingsReaderScreen : SearchableSettings { pref = readerPref.trueColor(), title = stringResource(R.string.pref_true_color), subtitle = stringResource(R.string.pref_true_color_summary), + enabled = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O, ), Preference.PreferenceItem.SwitchPreference( pref = readerPref.pageTransitions(), diff --git a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt index 6b5fceda7..bcbf7110f 100644 --- a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt +++ b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt @@ -79,7 +79,6 @@ fun ScreenTransition( targetState = navigator.lastItem, transitionSpec = transition, modifier = modifier, - label = "ScreenTransition", ) { screen -> navigator.saveableState("transition", screen) { content(screen) diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 4323200dd..822c66b81 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -171,19 +171,22 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { } override fun getPackageName(): String { - try { - // Override the value passed as X-Requested-With in WebView requests - val stackTrace = Looper.getMainLooper().thread.stackTrace - val chromiumElement = stackTrace.find { - it.className.equals( - "org.chromium.base.BuildInfo", - ignoreCase = true, - ) + // This causes freezes in Android 6/7 for some reason + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + try { + // Override the value passed as X-Requested-With in WebView requests + val stackTrace = Looper.getMainLooper().thread.stackTrace + val chromiumElement = stackTrace.find { + it.className.equals( + "org.chromium.base.BuildInfo", + ignoreCase = true, + ) + } + if (chromiumElement?.methodName.equals("getAll", ignoreCase = true)) { + return WebViewUtil.SPOOF_PACKAGE_NAME + } + } catch (e: Exception) { } - if (chromiumElement?.methodName.equals("getAll", ignoreCase = true)) { - return WebViewUtil.SPOOF_PACKAGE_NAME - } - } catch (e: Exception) { } return super.getPackageName() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt b/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt index fb1278614..e0a5ffe8e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.data.coil +import android.os.Build import androidx.core.graphics.drawable.toDrawable import coil.ImageLoader import coil.decode.DecodeResult @@ -47,7 +48,8 @@ class TachiyomiImageDecoder(private val resources: ImageSource, private val opti ImageUtil.findImageType(it) } return when (type) { - ImageUtil.ImageType.AVIF, ImageUtil.ImageType.JXL, ImageUtil.ImageType.HEIF -> true + ImageUtil.ImageType.AVIF, ImageUtil.ImageType.JXL -> true + ImageUtil.ImageType.HEIF -> Build.VERSION.SDK_INT < Build.VERSION_CODES.O else -> false } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index 22c19cab0..566da8e9c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -5,6 +5,7 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.net.Uri +import android.os.Build import androidx.core.net.toUri import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.BackupRestoreJob @@ -367,18 +368,20 @@ class NotificationReceiver : BroadcastReceiver() { When programmatically dismissing this notification, the group notification is not automatically dismissed. */ - val groupKey = context.notificationManager.activeNotifications.find { - it.id == notificationId - }?.groupKey + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + val groupKey = context.notificationManager.activeNotifications.find { + it.id == notificationId + }?.groupKey - if (groupId != null && groupId != 0 && !groupKey.isNullOrEmpty()) { - val notifications = context.notificationManager.activeNotifications.filter { - it.groupKey == groupKey - } + if (groupId != null && groupId != 0 && groupKey != null && groupKey.isNotEmpty()) { + val notifications = context.notificationManager.activeNotifications.filter { + it.groupKey == groupKey + } - if (notifications.size == 2) { - context.cancelNotification(groupId) - return + if (notifications.size == 2) { + context.cancelNotification(groupId) + return + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt index 0d785e3a6..6cc4efd33 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.extension.installer import android.app.Service import android.content.pm.PackageManager +import android.os.Build import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.extension.model.InstallStep import eu.kanade.tachiyomi.util.system.getUriSize @@ -49,7 +50,11 @@ class ShizukuInstaller(private val service: Service) : Installer(service) { try { val size = service.getUriSize(entry.uri) ?: throw IllegalStateException() service.contentResolver.openInputStream(entry.uri)!!.use { - val createCommand = "pm install-create --user current -r -i ${service.packageName} -S $size" + val createCommand = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + "pm install-create --user current -r -i ${service.packageName} -S $size" + } else { + "pm install-create -r -i ${service.packageName} -S $size" + } val createResult = exec(createCommand) sessionId = SESSION_ID_REGEX.find(createResult.out)?.value ?: throw RuntimeException("Failed to create install session") diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt index f86d36485..94a65ddcd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt @@ -2,7 +2,9 @@ package eu.kanade.tachiyomi.util.storage import android.content.Context import android.net.Uri +import android.os.Build import androidx.core.content.FileProvider +import androidx.core.net.toUri import eu.kanade.tachiyomi.BuildConfig import java.io.File @@ -15,7 +17,11 @@ val Context.cacheImageDir: File * @param context context of application */ fun File.getUriCompat(context: Context): Uri { - return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", this) + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", this) + } else { + this.toUri() + } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt index 18e16baac..8d72a9c86 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt @@ -18,7 +18,8 @@ fun Context.isOnline(): Boolean { val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false val maxTransport = when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 -> NetworkCapabilities.TRANSPORT_LOWPAN - else -> NetworkCapabilities.TRANSPORT_WIFI_AWARE + Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> NetworkCapabilities.TRANSPORT_WIFI_AWARE + else -> NetworkCapabilities.TRANSPORT_VPN } return (NetworkCapabilities.TRANSPORT_CELLULAR..maxTransport).any(networkCapabilities::hasTransport) } diff --git a/buildSrc/src/main/kotlin/AndroidConfig.kt b/buildSrc/src/main/kotlin/AndroidConfig.kt index 9a5cc2f6b..f63c07729 100644 --- a/buildSrc/src/main/kotlin/AndroidConfig.kt +++ b/buildSrc/src/main/kotlin/AndroidConfig.kt @@ -1,6 +1,6 @@ object AndroidConfig { const val compileSdk = 34 - const val minSdk = 26 + const val minSdk = 23 const val targetSdk = 29 const val ndk = "22.1.7171670" } 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 6547a46e0..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 @@ -1,5 +1,7 @@ package eu.kanade.tachiyomi.util.system +import android.annotation.TargetApi +import android.os.Build import android.webkit.WebResourceError import android.webkit.WebResourceRequest import android.webkit.WebResourceResponse @@ -26,6 +28,7 @@ abstract class WebViewClientCompat : WebViewClient() { ) { } + @TargetApi(Build.VERSION_CODES.N) final override fun shouldOverrideUrlLoading( view: WebView, request: WebResourceRequest, 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 b60bc8dc0..b3329e9b7 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 @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.util.system import android.annotation.SuppressLint import android.content.Context import android.content.pm.PackageManager +import android.os.Build import android.webkit.CookieManager import android.webkit.WebSettings import android.webkit.WebView @@ -34,11 +35,15 @@ object WebViewUtil { } fun getVersion(context: Context): String { - val webView = WebView.getCurrentWebViewPackage() ?: return "how did you get here?" - val pm = context.packageManager - val label = webView.applicationInfo.loadLabel(pm) - val version = webView.versionName - return "$label $version" + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val webView = WebView.getCurrentWebViewPackage() ?: return "how did you get here?" + val pm = context.packageManager + val label = webView.applicationInfo.loadLabel(pm) + val version = webView.versionName + "$label $version" + } else { + "Unknown" + } } fun supportsWebView(context: Context): Boolean { From db20d04c4b628a76dfdf7ce5e715ec2cf13de79a Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 4 Nov 2023 19:41:00 -0400 Subject: [PATCH 47/66] No-op app update checks for Android < 8 This effectively makes it the last release for the older Android versions. --- .../eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt index aa9e3a615..3809fd6c5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.data.updater import android.content.Context +import android.os.Build import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.util.system.isInstalledFromFDroid import tachiyomi.core.util.lang.withIOContext @@ -12,6 +13,11 @@ class AppUpdateChecker { private val getApplicationRelease: GetApplicationRelease by injectLazy() suspend fun checkForUpdate(context: Context, forceCheck: Boolean = false): GetApplicationRelease.Result { + // Disabling app update checks for older Android versions that we're going to drop support for + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { + return GetApplicationRelease.Result.NoNewUpdate + } + return withIOContext { val result = getApplicationRelease.await( GetApplicationRelease.Arguments( From 3a15c6b8438d1a740af0d6ffdec72347eec8cb83 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 4 Nov 2023 20:26:47 -0400 Subject: [PATCH 48/66] Show EOL message if update check no-ops due to unsupported Android version --- .../presentation/more/settings/screen/about/AboutScreen.kt | 3 +++ .../java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt | 2 +- .../domain/release/interactor/GetApplicationRelease.kt | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) 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 c12f3128e..6ae3bba16 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 @@ -228,6 +228,9 @@ object AboutScreen : Screen() { is GetApplicationRelease.Result.NoNewUpdate -> { context.toast(R.string.update_check_no_new_updates) } + is GetApplicationRelease.Result.OsTooOld -> { + context.toast(R.string.update_check_eol) + } else -> {} } } catch (e: Exception) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt index 3809fd6c5..5d4416315 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt @@ -15,7 +15,7 @@ class AppUpdateChecker { suspend fun checkForUpdate(context: Context, forceCheck: Boolean = false): GetApplicationRelease.Result { // Disabling app update checks for older Android versions that we're going to drop support for if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { - return GetApplicationRelease.Result.NoNewUpdate + return GetApplicationRelease.Result.OsTooOld } return withIOContext { 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 1a0ff4e4b..113e48af3 100644 --- a/domain/src/main/java/tachiyomi/domain/release/interactor/GetApplicationRelease.kt +++ b/domain/src/main/java/tachiyomi/domain/release/interactor/GetApplicationRelease.kt @@ -87,6 +87,7 @@ class GetApplicationRelease( sealed interface Result { data class NewUpdate(val release: Release) : Result data object NoNewUpdate : Result + data object OsTooOld : Result data object ThirdPartyInstallation : Result } } From 056dbaefda791b53240265c8e9562a01f17118c4 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 4 Nov 2023 23:21:24 -0400 Subject: [PATCH 49/66] Minor cleanup --- app/src/main/java/eu/kanade/tachiyomi/App.kt | 7 ++++--- .../eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 822c66b81..6cd282fbb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -11,6 +11,7 @@ import android.content.IntentFilter import android.os.Build import android.os.Looper import android.webkit.WebView +import androidx.core.content.ContextCompat import androidx.core.content.getSystemService import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner @@ -185,7 +186,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { if (chromiumElement?.methodName.equals("getAll", ignoreCase = true)) { return WebViewUtil.SPOOF_PACKAGE_NAME } - } catch (e: Exception) { + } catch (_: Exception) { } } return super.getPackageName() @@ -222,7 +223,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { fun register() { if (!registered) { - registerReceiver(this, IntentFilter(ACTION_DISABLE_INCOGNITO_MODE)) + ContextCompat.registerReceiver(this@App, this, IntentFilter(ACTION_DISABLE_INCOGNITO_MODE), ContextCompat.RECEIVER_NOT_EXPORTED) registered = true } } @@ -241,7 +242,7 @@ private const val ACTION_DISABLE_INCOGNITO_MODE = "tachi.action.DISABLE_INCOGNIT /** * Direct copy of Coil's internal SingletonDiskCache so that [MangaCoverFetcher] can access it. */ -internal object CoilDiskCache { +private object CoilDiskCache { private const val FOLDER_NAME = "image_cache" private var instance: DiskCache? = null diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt index 5d4416315..08a1cbbb7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt @@ -13,10 +13,10 @@ class AppUpdateChecker { private val getApplicationRelease: GetApplicationRelease by injectLazy() suspend fun checkForUpdate(context: Context, forceCheck: Boolean = false): GetApplicationRelease.Result { - // Disabling app update checks for older Android versions that we're going to drop support for if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { return GetApplicationRelease.Result.OsTooOld } + // Disable app update checks for older Android versions that we're going to drop support for return withIOContext { val result = getApplicationRelease.await( From 1d144e67678a99ec7198e5efcb1410b5da4bc42e Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 4 Nov 2023 23:28:41 -0400 Subject: [PATCH 50/66] Restrict line length with ktlint --- .editorconfig | 13 +- .../domain/chapter/model/ChapterFilter.kt | 7 +- .../source/service/SourcePreferences.kt | 12 +- .../domain/track/interactor/AddTracks.kt | 5 +- .../track/service/DelayedTrackingUpdateJob.kt | 4 +- .../browse/MigrateSourceScreen.kt | 20 ++- .../presentation/browse/SourcesScreen.kt | 8 +- .../browse/components/BaseSourceItem.kt | 4 +- .../category/components/CategoryListItem.kt | 5 +- .../kanade/presentation/manga/MangaScreen.kt | 4 +- .../manga/components/MangaInfoHeader.kt | 10 +- .../eu/kanade/presentation/more/MoreScreen.kt | 4 +- .../more/settings/screen/Commons.kt | 3 +- .../screen/SettingsAppearanceScreen.kt | 4 +- .../settings/screen/debug/WorkerInfoScreen.kt | 4 +- .../settings/widget/TriStateListDialog.kt | 12 +- .../reader/appbars/ChapterNavigator.kt | 8 +- .../reader/appbars/ReaderAppBars.kt | 4 +- .../webview/WebViewScreenContent.kt | 4 +- app/src/main/java/eu/kanade/tachiyomi/App.kt | 7 +- .../java/eu/kanade/tachiyomi/Migrations.kt | 27 +++- .../tachiyomi/data/backup/BackupNotifier.kt | 42 ++++++- .../tachiyomi/data/backup/BackupRestorer.kt | 43 ++++++- .../tachiyomi/data/download/DownloadCache.kt | 5 +- .../data/download/DownloadNotifier.kt | 5 +- .../tachiyomi/data/download/Downloader.kt | 14 ++- .../data/library/LibraryUpdateJob.kt | 14 ++- .../data/library/LibraryUpdateNotifier.kt | 56 +++++++-- .../data/notification/NotificationHandler.kt | 14 ++- .../data/notification/NotificationReceiver.kt | 118 +++++++++++++++--- .../tachiyomi/data/track/kavita/KavitaApi.kt | 27 ++-- .../data/track/myanimelist/MyAnimeListApi.kt | 5 +- .../tachiyomi/data/track/suwayomi/Suwayomi.kt | 4 +- .../data/updater/AppUpdateChecker.kt | 4 +- .../data/updater/AppUpdateNotifier.kt | 14 ++- .../installer/PackageInstallerInstaller.kt | 7 +- .../util/ExtensionInstallReceiver.kt | 4 +- .../tachiyomi/source/AndroidSourceManager.kt | 4 +- .../source/browse/BrowseSourceScreenModel.kt | 9 +- .../ui/library/LibraryScreenModel.kt | 3 +- .../kanade/tachiyomi/ui/library/LibraryTab.kt | 4 +- .../kanade/tachiyomi/ui/main/MainActivity.kt | 6 +- .../kanade/tachiyomi/ui/manga/MangaScreen.kt | 24 +++- .../tachiyomi/ui/reader/ReaderViewModel.kt | 22 +++- .../ui/reader/loader/ChapterLoader.kt | 8 +- .../ui/reader/setting/OrientationType.kt | 56 +++++++-- .../ui/reader/setting/ReaderPreferences.kt | 10 +- .../ui/reader/setting/ReadingModeType.kt | 6 +- .../kanade/tachiyomi/ui/updates/UpdatesTab.kt | 4 +- .../tachiyomi/util/storage/FileExtensions.kt | 12 +- .../util/system/ContextExtensions.kt | 9 +- .../util/system/NotificationExtensions.kt | 5 +- .../tachiyomi/util/view/ViewExtensions.kt | 3 +- .../network/interceptor/WebViewInterceptor.kt | 7 +- .../tachiyomi/core/util/system/ImageUtil.kt | 22 +++- .../data/source/SourcePagingSource.kt | 5 +- .../domain/chapter/model/ChapterUpdate.kt | 15 ++- .../core/components/VerticalFastScroller.kt | 10 +- .../presentation/core/util/Scrollbar.kt | 6 +- .../widget/components/UpdatesWidget.kt | 5 +- .../tachiyomi/source/local/LocalSource.kt | 8 +- 61 files changed, 660 insertions(+), 148 deletions(-) diff --git a/.editorconfig b/.editorconfig index d1f195728..fc6b3c0c8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,7 +1,8 @@ [*.{kt,kts}] -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 +max_line_length = 120 +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 diff --git a/app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt b/app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt index 6ddf2f33f..ad476418f 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt @@ -23,7 +23,12 @@ fun List.applyFilters(manga: Manga, downloadManager: DownloadManager): .filter { chapter -> applyFilter(bookmarkedFilter) { chapter.bookmark } } .filter { chapter -> applyFilter(downloadedFilter) { - val downloaded = downloadManager.isChapterDownloaded(chapter.name, chapter.scanlator, manga.title, manga.source) + val downloaded = downloadManager.isChapterDownloaded( + chapter.name, + chapter.scanlator, + manga.title, + manga.source, + ) downloaded || isLocalManga } } diff --git a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt index 67f5c3190..0fe4ce23f 100644 --- a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt @@ -11,7 +11,12 @@ class SourcePreferences( private val preferenceStore: PreferenceStore, ) { - fun sourceDisplayMode() = preferenceStore.getObject("pref_display_mode_catalogue", LibraryDisplayMode.default, LibraryDisplayMode.Serializer::serialize, LibraryDisplayMode.Serializer::deserialize) + fun sourceDisplayMode() = preferenceStore.getObject( + "pref_display_mode_catalogue", + LibraryDisplayMode.default, + LibraryDisplayMode.Serializer::serialize, + LibraryDisplayMode.Serializer::deserialize, + ) fun enabledLanguages() = preferenceStore.getStringSet("source_languages", LocaleHelper.getDefaultEnabledLanguages()) @@ -28,7 +33,10 @@ class SourcePreferences( fun migrationSortingMode() = preferenceStore.getEnum("pref_migration_sorting", SetMigrateSorting.Mode.ALPHABETICAL) - fun migrationSortingDirection() = preferenceStore.getEnum("pref_migration_direction", SetMigrateSorting.Direction.ASCENDING) + fun migrationSortingDirection() = preferenceStore.getEnum( + "pref_migration_direction", + SetMigrateSorting.Direction.ASCENDING, + ) fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0) 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 885a6249f..70e612c3c 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 @@ -61,7 +61,10 @@ class AddTracks( ?.readAt firstReadChapterDate?.let { - val startDate = firstReadChapterDate.time.convertEpochMillisZone(ZoneOffset.systemDefault(), ZoneOffset.UTC) + val startDate = firstReadChapterDate.time.convertEpochMillisZone( + ZoneOffset.systemDefault(), + ZoneOffset.UTC, + ) track = track.copy( startDate = startDate, ) 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 32be14241..ad7c3f6b9 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 @@ -43,7 +43,9 @@ class DelayedTrackingUpdateJob(private val context: Context, workerParams: Worke track?.copy(lastChapterRead = it.lastChapterRead.toDouble()) } .forEach { track -> - logcat(LogPriority.DEBUG) { "Updating delayed track item: ${track.mangaId}, last chapter read: ${track.lastChapterRead}" } + logcat(LogPriority.DEBUG) { + "Updating delayed track item: ${track.mangaId}, last chapter read: ${track.lastChapterRead}" + } trackChapter.await(context, track.mangaId, track.lastChapterRead) } } diff --git a/app/src/main/java/eu/kanade/presentation/browse/MigrateSourceScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/MigrateSourceScreen.kt index 2c4f4fc46..0733fc43e 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/MigrateSourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/MigrateSourceScreen.kt @@ -102,14 +102,26 @@ private fun MigrateSourceList( IconButton(onClick = onToggleSortingMode) { when (sortingMode) { - SetMigrateSorting.Mode.ALPHABETICAL -> Icon(Icons.Outlined.SortByAlpha, contentDescription = stringResource(R.string.action_sort_alpha)) - SetMigrateSorting.Mode.TOTAL -> Icon(Icons.Outlined.Numbers, contentDescription = stringResource(R.string.action_sort_count)) + SetMigrateSorting.Mode.ALPHABETICAL -> Icon( + Icons.Outlined.SortByAlpha, + contentDescription = stringResource(R.string.action_sort_alpha), + ) + SetMigrateSorting.Mode.TOTAL -> Icon( + Icons.Outlined.Numbers, + contentDescription = stringResource(R.string.action_sort_count), + ) } } IconButton(onClick = onToggleSortingDirection) { when (sortingDirection) { - SetMigrateSorting.Direction.ASCENDING -> Icon(Icons.Outlined.ArrowUpward, contentDescription = stringResource(R.string.action_asc)) - SetMigrateSorting.Direction.DESCENDING -> Icon(Icons.Outlined.ArrowDownward, contentDescription = stringResource(R.string.action_desc)) + SetMigrateSorting.Direction.ASCENDING -> Icon( + Icons.Outlined.ArrowUpward, + contentDescription = stringResource(R.string.action_asc), + ) + SetMigrateSorting.Direction.DESCENDING -> Icon( + Icons.Outlined.ArrowDownward, + contentDescription = stringResource(R.string.action_desc), + ) } } } diff --git a/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt index de5434595..d6a8c7186 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt @@ -144,7 +144,13 @@ private fun SourcePinButton( onClick: () -> Unit, ) { val icon = if (isPinned) Icons.Filled.PushPin else Icons.Outlined.PushPin - val tint = if (isPinned) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground.copy(alpha = SecondaryItemAlpha) + val tint = if (isPinned) { + MaterialTheme.colorScheme.primary + } else { + MaterialTheme.colorScheme.onBackground.copy( + alpha = SecondaryItemAlpha, + ) + } val description = if (isPinned) R.string.action_unpin else R.string.action_pin IconButton(onClick = onClick) { Icon( diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BaseSourceItem.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BaseSourceItem.kt index 08d3e845c..b8b9e0d7a 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BaseSourceItem.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BaseSourceItem.kt @@ -25,7 +25,9 @@ fun BaseSourceItem( action: @Composable RowScope.(Source) -> Unit = {}, content: @Composable RowScope.(Source, String?) -> Unit = defaultContent, ) { - val sourceLangString = LocaleHelper.getSourceDisplayName(source.lang, LocalContext.current).takeIf { showLanguageInContent } + val sourceLangString = LocaleHelper.getSourceDisplayName(source.lang, LocalContext.current).takeIf { + showLanguageInContent + } BaseBrowseItem( modifier = modifier, onClickItem = onClickItem, diff --git a/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt b/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt index 565ea7b35..87d9ad06e 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/CategoryListItem.kt @@ -71,7 +71,10 @@ fun CategoryListItem( } Spacer(modifier = Modifier.weight(1f)) IconButton(onClick = onRename) { - Icon(imageVector = Icons.Outlined.Edit, contentDescription = stringResource(R.string.action_rename_category)) + Icon( + imageVector = Icons.Outlined.Edit, + contentDescription = stringResource(R.string.action_rename_category), + ) } IconButton(onClick = onDelete) { Icon(imageVector = Icons.Outlined.Delete, contentDescription = stringResource(R.string.action_delete)) 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 83b35bd46..38e8b7814 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -614,7 +614,9 @@ fun MangaScreenLargeImpl( val isReading = remember(state.chapters) { state.chapters.fastAny { it.chapter.read } } - Text(text = stringResource(if (isReading) R.string.action_resume else R.string.action_start)) + Text( + text = stringResource(if (isReading) R.string.action_resume else R.string.action_start), + ) }, icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) }, onClick = onContinueReading, 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 570812442..cbe3f9b28 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 @@ -189,7 +189,11 @@ fun MangaActionRow( ) if (onEditIntervalClicked != null && fetchInterval != null) { MangaActionButton( - title = pluralStringResource(id = R.plurals.day, count = fetchInterval.absoluteValue, fetchInterval.absoluteValue), + title = pluralStringResource( + id = R.plurals.day, + count = fetchInterval.absoluteValue, + fetchInterval.absoluteValue, + ), icon = Icons.Default.HourglassEmpty, color = if (isUserIntervalMode) MaterialTheme.colorScheme.primary else defaultActionButtonColor, onClick = onEditIntervalClicked, @@ -587,7 +591,9 @@ private fun MangaSummary( val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_caret_down) Icon( painter = rememberAnimatedVectorPainter(image, !expanded), - contentDescription = stringResource(if (expanded) R.string.manga_info_collapse else R.string.manga_info_expand), + contentDescription = stringResource( + if (expanded) R.string.manga_info_collapse else R.string.manga_info_expand, + ), tint = MaterialTheme.colorScheme.onBackground, modifier = Modifier.background(Brush.radialGradient(colors = colors.asReversed())), ) 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 6f7e9e3d7..50ade6318 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,9 @@ fun MoreScreen( WarningBanner( textRes = R.string.fdroid_warning, modifier = Modifier.clickable { - uriHandler.openUri("https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds") + 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/Commons.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/Commons.kt index 641a48f35..44cc49ef2 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/Commons.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/Commons.kt @@ -31,7 +31,8 @@ fun getCategoriesLabel( val includedItemsText = when { // Some selected, but not all - includedCategories.isNotEmpty() && includedCategories.size != allCategories.size -> includedCategories.joinToString { it.visualName(context) } + includedCategories.isNotEmpty() && includedCategories.size != allCategories.size -> + includedCategories.joinToString { it.visualName(context) } // All explicitly selected includedCategories.size == allCategories.size -> stringResource(R.string.all) allExcluded -> stringResource(R.string.none) 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 4540aee95..4c7243a5c 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 @@ -120,7 +120,9 @@ object SettingsAppearanceScreen : SearchableSettings { uiPreferences: UiPreferences, ): Preference.PreferenceGroup { val langs = remember { getLangs(context) } - var currentLanguage by remember { mutableStateOf(AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "") } + var currentLanguage by remember { + mutableStateOf(AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "") + } val now = remember { Date().time } val dateFormat by uiPreferences.dateFormat().collectAsState() diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt index e7e815df6..dc9f6e7de 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/WorkerInfoScreen.kt @@ -115,7 +115,9 @@ class WorkerInfoScreen : Screen() { private val workManager = context.workManager val finished = workManager - .getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)) + .getWorkInfosLiveData( + WorkQuery.fromStates(WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED), + ) .asFlow() .map(::constructString) .stateIn(ioCoroutineScope, SharingStarted.WhileSubscribed(), "") diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt index 87e3d7da0..220c9a318 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TriStateListDialog.kt @@ -115,8 +115,16 @@ fun TriStateListDialog( } } - if (!listState.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter)) - if (!listState.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter)) + if (!listState.isScrolledToStart()) { + HorizontalDivider( + modifier = Modifier.align(Alignment.TopCenter), + ) + } + if (!listState.isScrolledToEnd()) { + HorizontalDivider( + modifier = Modifier.align(Alignment.BottomCenter), + ) + } } } }, diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt index 31a9a905f..ede1ae332 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt @@ -77,7 +77,9 @@ fun ChapterNavigator( ) { Icon( imageVector = Icons.Outlined.SkipPrevious, - contentDescription = stringResource(if (isRtl) R.string.action_next_chapter else R.string.action_previous_chapter), + contentDescription = stringResource( + if (isRtl) R.string.action_next_chapter else R.string.action_previous_chapter, + ), ) } @@ -127,7 +129,9 @@ fun ChapterNavigator( ) { Icon( imageVector = Icons.Outlined.SkipNext, - contentDescription = stringResource(if (isRtl) R.string.action_previous_chapter else R.string.action_next_chapter), + contentDescription = stringResource( + if (isRtl) R.string.action_previous_chapter else R.string.action_next_chapter, + ), ) } } diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt index e044d5ccf..7b360b04d 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -99,7 +99,9 @@ fun ReaderAppBars( AppBarActions( listOfNotNull( AppBar.Action( - title = stringResource(if (bookmarked) R.string.action_remove_bookmark else R.string.action_bookmark), + title = stringResource( + if (bookmarked) R.string.action_remove_bookmark else R.string.action_bookmark, + ), icon = if (bookmarked) Icons.Outlined.Bookmark else Icons.Outlined.BookmarkBorder, onClick = onToggleBookmarked, ), 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 823b5bfc3..ce64a1fdc 100644 --- a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt +++ b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt @@ -173,7 +173,9 @@ fun WebViewScreenContent( modifier = Modifier .clip(MaterialTheme.shapes.small) .clickable { - uriHandler.openUri("https://tachiyomi.org/docs/guides/troubleshooting/#cloudflare") + uriHandler.openUri( + "https://tachiyomi.org/docs/guides/troubleshooting/#cloudflare", + ) }, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 6cd282fbb..8459c8073 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -223,7 +223,12 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { fun register() { if (!registered) { - ContextCompat.registerReceiver(this@App, this, IntentFilter(ACTION_DISABLE_INCOGNITO_MODE), ContextCompat.RECEIVER_NOT_EXPORTED) + ContextCompat.registerReceiver( + this@App, + this, + IntentFilter(ACTION_DISABLE_INCOGNITO_MODE), + ContextCompat.RECEIVER_NOT_EXPORTED, + ) registered = true } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index b1cbe9d27..bd672e316 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -121,13 +121,22 @@ object Migrations { } } prefs.edit { - putInt(libraryPreferences.filterDownloaded().key(), convertBooleanPrefToTriState("pref_filter_downloaded_key")) + putInt( + libraryPreferences.filterDownloaded().key(), + convertBooleanPrefToTriState("pref_filter_downloaded_key"), + ) remove("pref_filter_downloaded_key") - putInt(libraryPreferences.filterUnread().key(), convertBooleanPrefToTriState("pref_filter_unread_key")) + putInt( + libraryPreferences.filterUnread().key(), + convertBooleanPrefToTriState("pref_filter_unread_key"), + ) remove("pref_filter_unread_key") - putInt(libraryPreferences.filterCompleted().key(), convertBooleanPrefToTriState("pref_filter_completed_key")) + putInt( + libraryPreferences.filterCompleted().key(), + convertBooleanPrefToTriState("pref_filter_completed_key"), + ) remove("pref_filter_completed_key") } } @@ -242,7 +251,10 @@ object Migrations { if (oldSecureScreen) { securityPreferences.secureScreen().set(SecurityPreferences.SecureScreenMode.ALWAYS) } - if (DeviceUtil.isMiui && basePreferences.extensionInstaller().get() == BasePreferences.ExtensionInstaller.PACKAGEINSTALLER) { + if ( + DeviceUtil.isMiui && + basePreferences.extensionInstaller().get() == BasePreferences.ExtensionInstaller.PACKAGEINSTALLER + ) { basePreferences.extensionInstaller().set(BasePreferences.ExtensionInstaller.LEGACY) } } @@ -259,7 +271,12 @@ object Migrations { if (oldVersion < 81) { // Handle renamed enum values prefs.edit { - val newSortingMode = when (val oldSortingMode = prefs.getString(libraryPreferences.sortingMode().key(), "ALPHABETICAL")) { + val newSortingMode = when ( + val oldSortingMode = prefs.getString( + libraryPreferences.sortingMode().key(), + "ALPHABETICAL", + ) + ) { "LAST_CHECKED" -> "LAST_MANGA_UPDATE" "UNREAD" -> "UNREAD_COUNT" "DATE_FETCHED" -> "CHAPTER_FETCH_DATE" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupNotifier.kt index f75923278..49b7ee0dd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupNotifier.kt @@ -20,7 +20,9 @@ class BackupNotifier(private val context: Context) { private val preferences: SecurityPreferences by injectLazy() - private val progressNotificationBuilder = context.notificationBuilder(Notifications.CHANNEL_BACKUP_RESTORE_PROGRESS) { + private val progressNotificationBuilder = context.notificationBuilder( + Notifications.CHANNEL_BACKUP_RESTORE_PROGRESS, + ) { setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher)) setSmallIcon(R.drawable.ic_tachi) setAutoCancel(false) @@ -28,7 +30,9 @@ class BackupNotifier(private val context: Context) { setOnlyAlertOnce(true) } - private val completeNotificationBuilder = context.notificationBuilder(Notifications.CHANNEL_BACKUP_RESTORE_COMPLETE) { + private val completeNotificationBuilder = context.notificationBuilder( + Notifications.CHANNEL_BACKUP_RESTORE_COMPLETE, + ) { setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher)) setSmallIcon(R.drawable.ic_tachi) setAutoCancel(false) @@ -72,14 +76,25 @@ class BackupNotifier(private val context: Context) { addAction( R.drawable.ic_share_24dp, context.getString(R.string.action_share), - NotificationReceiver.shareBackupPendingBroadcast(context, unifile.uri, Notifications.ID_BACKUP_COMPLETE), + NotificationReceiver.shareBackupPendingBroadcast( + context, + unifile.uri, + Notifications.ID_BACKUP_COMPLETE, + ), ) show(Notifications.ID_BACKUP_COMPLETE) } } - fun showRestoreProgress(content: String = "", contentTitle: String = context.getString(R.string.restoring_backup), progress: Int = 0, maxAmount: Int = 100): NotificationCompat.Builder { + fun showRestoreProgress( + content: String = "", + contentTitle: String = context.getString( + R.string.restoring_backup, + ), + progress: Int = 0, + maxAmount: Int = 100, + ): NotificationCompat.Builder { val builder = with(progressNotificationBuilder) { setContentTitle(contentTitle) @@ -114,7 +129,15 @@ class BackupNotifier(private val context: Context) { } } - fun showRestoreComplete(time: Long, errorCount: Int, path: String?, file: String?, contentTitle: String = context.getString(R.string.restore_completed)) { + fun showRestoreComplete( + time: Long, + errorCount: Int, + path: String?, + file: String?, + contentTitle: String = context.getString( + R.string.restore_completed, + ), + ) { context.cancelNotification(Notifications.ID_RESTORE_PROGRESS) val timeString = context.getString( @@ -127,7 +150,14 @@ class BackupNotifier(private val context: Context) { with(completeNotificationBuilder) { setContentTitle(contentTitle) - setContentText(context.resources.getQuantityString(R.plurals.restore_completed_message, errorCount, timeString, errorCount)) + setContentText( + context.resources.getQuantityString( + R.plurals.restore_completed_message, + errorCount, + timeString, + errorCount, + ), + ) clearActions() if (errorCount > 0 && !path.isNullOrEmpty() && !file.isNullOrEmpty()) { 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 726f20cd3..54c153b33 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 @@ -88,7 +88,13 @@ class BackupRestorer( val logFile = writeErrorLog() if (sync) { - notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name, contentTitle = context.getString(R.string.library_sync_complete)) + notifier.showRestoreComplete( + time, + errors.size, + logFile.parent, + logFile.name, + contentTitle = context.getString(R.string.library_sync_complete), + ) } else { notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name) } @@ -183,7 +189,12 @@ class BackupRestorer( ) restoreProgress += 1 - showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories), context.getString(R.string.restoring_backup)) + showRestoreProgress( + restoreProgress, + restoreAmount, + context.getString(R.string.categories), + context.getString(R.string.restoring_backup), + ) } private suspend fun restoreManga(backupManga: BackupManga, backupCategories: List, sync: Boolean) { @@ -214,9 +225,19 @@ class BackupRestorer( restoreProgress += 1 if (sync) { - showRestoreProgress(restoreProgress, restoreAmount, manga.title, context.getString(R.string.syncing_library)) + showRestoreProgress( + restoreProgress, + restoreAmount, + manga.title, + context.getString(R.string.syncing_library), + ) } else { - showRestoreProgress(restoreProgress, restoreAmount, manga.title, context.getString(R.string.restoring_backup)) + showRestoreProgress( + restoreProgress, + restoreAmount, + manga.title, + context.getString(R.string.restoring_backup), + ) } } @@ -603,7 +624,12 @@ class BackupRestorer( BackupCreateJob.setupTask(context) restoreProgress += 1 - showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.app_settings), context.getString(R.string.restoring_backup)) + showRestoreProgress( + restoreProgress, + restoreAmount, + context.getString(R.string.app_settings), + context.getString(R.string.restoring_backup), + ) } private fun restoreSourcePreferences(preferences: List) { @@ -613,7 +639,12 @@ class BackupRestorer( } restoreProgress += 1 - showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.source_settings), context.getString(R.string.restoring_backup)) + 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/data/download/DownloadCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt index 81dfd7168..018a55f1b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt @@ -148,7 +148,10 @@ class DownloadCache( if (sourceDir != null) { val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(mangaTitle)] if (mangaDir != null) { - return provider.getValidChapterDirNames(chapterName, chapterScanlator).any { it in mangaDir.chapterDirs } + return provider.getValidChapterDirNames( + chapterName, + chapterScanlator, + ).any { it in mangaDir.chapterDirs } } } return false diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt index a4b06792b..bfbf3117d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt @@ -95,7 +95,10 @@ internal class DownloadNotifier(private val context: Context) { } else { val title = download.manga.title.chop(15) val quotedTitle = Pattern.quote(title) - val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "") + val chapter = download.chapter.name.replaceFirst( + "$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), + "", + ) setContentTitle("$title - $chapter".chop(30)) setContentText(downloadingProgressText) } 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 9a15967f4..9af19d77e 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 @@ -324,7 +324,11 @@ class Downloader( val availSpace = DiskUtil.getAvailableStorageSpace(mangaDir) if (availSpace != -1L && availSpace < MIN_DISK_SPACE) { download.status = Download.State.ERROR - notifier.onError(context.getString(R.string.download_insufficient_space), download.chapter.name, download.manga.title) + notifier.onError( + context.getString(R.string.download_insufficient_space), + download.chapter.name, + download.manga.title, + ) return } @@ -432,13 +436,17 @@ class Downloader( tmpFile?.delete() // Try to find the image file - val imageFile = tmpDir.listFiles()?.firstOrNull { it.name!!.startsWith("$filename.") || it.name!!.startsWith("${filename}__001") } + val imageFile = tmpDir.listFiles()?.firstOrNull { + it.name!!.startsWith("$filename.") || it.name!!.startsWith("${filename}__001") + } try { // If the image is already downloaded, do nothing. Otherwise download from network val file = when { imageFile != null -> imageFile - chapterCache.isImageInCache(page.imageUrl!!) -> copyImageFromCache(chapterCache.getImageFile(page.imageUrl!!), tmpDir, filename) + chapterCache.isImageInCache( + page.imageUrl!!, + ) -> copyImageFromCache(chapterCache.getImageFile(page.imageUrl!!), tmpDir, filename) else -> downloadImage(page, download.source, tmpDir, filename) } 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 3554722a0..5822015a6 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 @@ -296,7 +296,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet 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) + is SourceNotInstalledException -> context.getString( + R.string.loader_not_implemented_error, + ) else -> e.message } failedUpdates.add(manga to errorMessage) @@ -500,7 +502,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet if (interval > 0) { val restrictions = preferences.autoUpdateDeviceRestrictions().get() val constraints = Constraints( - requiredNetworkType = if (DEVICE_NETWORK_NOT_METERED in restrictions) { NetworkType.UNMETERED } else { NetworkType.CONNECTED }, + requiredNetworkType = if (DEVICE_NETWORK_NOT_METERED in restrictions) { + NetworkType.UNMETERED + } else { NetworkType.CONNECTED }, requiresCharging = DEVICE_CHARGING in restrictions, requiresBatteryNotLow = true, ) @@ -517,7 +521,11 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet .setBackoffCriteria(BackoffPolicy.LINEAR, 10, TimeUnit.MINUTES) .build() - context.workManager.enqueueUniquePeriodicWork(WORK_NAME_AUTO, ExistingPeriodicWorkPolicy.UPDATE, request) + context.workManager.enqueueUniquePeriodicWork( + WORK_NAME_AUTO, + ExistingPeriodicWorkPolicy.UPDATE, + request, + ) } else { context.workManager.cancelUniqueWork(WORK_NAME_AUTO) } 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 833680ba4..cc3a0d8d3 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 @@ -82,7 +82,12 @@ class LibraryUpdateNotifier(private val context: Context) { } else { val updatingText = manga.joinToString("\n") { it.title.chop(40) } progressNotificationBuilder - .setContentTitle(context.getString(R.string.notification_updating_progress, percentFormatter.format(current.toFloat() / total))) + .setContentTitle( + context.getString( + R.string.notification_updating_progress, + percentFormatter.format(current.toFloat() / total), + ), + ) .setStyle(NotificationCompat.BigTextStyle().bigText(updatingText)) } @@ -166,7 +171,13 @@ class LibraryUpdateNotifier(private val context: Context) { if (updates.size == 1 && !preferences.hideNotificationContent().get()) { setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN)) } else { - setContentText(context.resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size)) + setContentText( + context.resources.getQuantityString( + R.plurals.notification_new_chapters_summary, + updates.size, + updates.size, + ), + ) if (!preferences.hideNotificationContent().get()) { setStyle( @@ -196,7 +207,10 @@ class LibraryUpdateNotifier(private val context: Context) { launchUI { context.notify( updates.map { (manga, chapters) -> - NotificationManagerCompat.NotificationWithIdAndTag(manga.id.hashCode(), createNewChaptersNotification(manga, chapters)) + NotificationManagerCompat.NotificationWithIdAndTag( + manga.id.hashCode(), + createNewChaptersNotification(manga, chapters), + ) }, ) } @@ -292,17 +306,28 @@ class LibraryUpdateNotifier(private val context: Context) { // No sensible chapter numbers to show (i.e. no chapters have parsed chapter number) 0 -> { // "1 new chapter" or "5 new chapters" - context.resources.getQuantityString(R.plurals.notification_chapters_generic, chapters.size, chapters.size) + context.resources.getQuantityString( + R.plurals.notification_chapters_generic, + chapters.size, + chapters.size, + ) } // Only 1 chapter has a parsed chapter number 1 -> { val remaining = chapters.size - displayableChapterNumbers.size if (remaining == 0) { // "Chapter 2.5" - context.resources.getString(R.string.notification_chapters_single, displayableChapterNumbers.first()) + context.resources.getString( + R.string.notification_chapters_single, + displayableChapterNumbers.first(), + ) } else { // "Chapter 2.5 and 10 more" - context.resources.getString(R.string.notification_chapters_single_and_more, displayableChapterNumbers.first(), remaining) + context.resources.getString( + R.string.notification_chapters_single_and_more, + displayableChapterNumbers.first(), + remaining, + ) } } // Everything else (i.e. multiple parsed chapter numbers) @@ -312,10 +337,18 @@ class LibraryUpdateNotifier(private val context: Context) { // "Chapters 1, 2.5, 3, 4, 5 and 10 more" val remaining = displayableChapterNumbers.size - NOTIF_MAX_CHAPTERS val joinedChapterNumbers = displayableChapterNumbers.take(NOTIF_MAX_CHAPTERS).joinToString(", ") - context.resources.getQuantityString(R.plurals.notification_chapters_multiple_and_more, remaining, joinedChapterNumbers, remaining) + context.resources.getQuantityString( + R.plurals.notification_chapters_multiple_and_more, + remaining, + joinedChapterNumbers, + remaining, + ) } else { // "Chapters 1, 2.5, 3" - context.resources.getString(R.string.notification_chapters_multiple, displayableChapterNumbers.joinToString(", ")) + context.resources.getString( + R.string.notification_chapters_multiple, + displayableChapterNumbers.joinToString(", "), + ) } } } @@ -329,7 +362,12 @@ class LibraryUpdateNotifier(private val context: Context) { flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP action = Constants.SHORTCUT_UPDATES } - return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getActivity( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt index e271294c9..aba7de79d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt @@ -23,7 +23,12 @@ object NotificationHandler { flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP action = Constants.SHORTCUT_DOWNLOADS } - return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getActivity( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -37,7 +42,12 @@ object NotificationHandler { setDataAndType(uri, "image/*") flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION } - return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getActivity( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index 566da8e9c..8f33a6366 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -306,7 +306,12 @@ class NotificationReceiver : BroadcastReceiver() { val intent = Intent(context, NotificationReceiver::class.java).apply { action = ACTION_RESUME_DOWNLOADS } - return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -319,7 +324,12 @@ class NotificationReceiver : BroadcastReceiver() { val intent = Intent(context, NotificationReceiver::class.java).apply { action = ACTION_PAUSE_DOWNLOADS } - return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -332,7 +342,12 @@ class NotificationReceiver : BroadcastReceiver() { val intent = Intent(context, NotificationReceiver::class.java).apply { action = ACTION_CLEAR_DOWNLOADS } - return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -347,7 +362,12 @@ class NotificationReceiver : BroadcastReceiver() { action = ACTION_DISMISS_NOTIFICATION putExtra(EXTRA_NOTIFICATION_ID, notificationId) } - return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -402,7 +422,12 @@ class NotificationReceiver : BroadcastReceiver() { putExtra(EXTRA_FILE_LOCATION, path) putExtra(EXTRA_NOTIFICATION_ID, notificationId) } - return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -419,7 +444,12 @@ class NotificationReceiver : BroadcastReceiver() { putExtra(EXTRA_FILE_LOCATION, path) putExtra(EXTRA_NOTIFICATION_ID, notificationId) } - return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -431,7 +461,12 @@ class NotificationReceiver : BroadcastReceiver() { */ internal fun openChapterPendingActivity(context: Context, manga: Manga, chapter: Chapter): PendingIntent { val newIntent = ReaderActivity.newIntent(context, manga.id, chapter.id) - return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getActivity( + context, + manga.id.hashCode(), + newIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -447,7 +482,12 @@ class NotificationReceiver : BroadcastReceiver() { .putExtra(Constants.MANGA_EXTRA, manga.id) .putExtra("notificationId", manga.id.hashCode()) .putExtra("groupId", groupId) - return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getActivity( + context, + manga.id.hashCode(), + newIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -469,7 +509,12 @@ class NotificationReceiver : BroadcastReceiver() { putExtra(EXTRA_NOTIFICATION_ID, manga.id.hashCode()) putExtra(EXTRA_GROUP_ID, groupId) } - return PendingIntent.getBroadcast(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + manga.id.hashCode(), + newIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -491,7 +536,12 @@ class NotificationReceiver : BroadcastReceiver() { putExtra(EXTRA_NOTIFICATION_ID, manga.id.hashCode()) putExtra(EXTRA_GROUP_ID, groupId) } - return PendingIntent.getBroadcast(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + manga.id.hashCode(), + newIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -504,7 +554,12 @@ class NotificationReceiver : BroadcastReceiver() { val intent = Intent(context, NotificationReceiver::class.java).apply { action = ACTION_CANCEL_LIBRARY_UPDATE } - return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -513,12 +568,21 @@ class NotificationReceiver : BroadcastReceiver() { * @param context context of application * @return [PendingIntent] */ - internal fun downloadAppUpdatePendingBroadcast(context: Context, url: String, title: String? = null): PendingIntent { + internal fun downloadAppUpdatePendingBroadcast( + context: Context, + url: String, + title: String? = null, + ): PendingIntent { return Intent(context, NotificationReceiver::class.java).run { action = ACTION_START_APP_UPDATE putExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_URL, url) title?.let { putExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_TITLE, it) } - PendingIntent.getBroadcast(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + PendingIntent.getBroadcast( + context, + 0, + this, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } } @@ -529,7 +593,12 @@ class NotificationReceiver : BroadcastReceiver() { val intent = Intent(context, NotificationReceiver::class.java).apply { action = ACTION_CANCEL_APP_UPDATE_DOWNLOAD } - return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -543,7 +612,12 @@ class NotificationReceiver : BroadcastReceiver() { action = Constants.SHORTCUT_EXTENSIONS addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) } - return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getActivity( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -560,7 +634,12 @@ class NotificationReceiver : BroadcastReceiver() { putExtra(EXTRA_URI, uri) putExtra(EXTRA_NOTIFICATION_ID, notificationId) } - return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } /** @@ -591,7 +670,12 @@ class NotificationReceiver : BroadcastReceiver() { action = ACTION_CANCEL_RESTORE putExtra(EXTRA_NOTIFICATION_ID, notificationId) } - return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + return PendingIntent.getBroadcast( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt index 6abc3bd7e..5eb753e03 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt @@ -48,11 +48,15 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor when (it.code) { 200 -> return it.parseAs().token 401 -> { - logcat(LogPriority.WARN) { "Unauthorized / api key not valid: Cleaned api URL: $apiUrl, Api key is empty: ${apiKey.isEmpty()}" } + logcat(LogPriority.WARN) { + "Unauthorized / API key not valid: API URL: $apiUrl, empty API key: ${apiKey.isEmpty()}" + } throw IOException("Unauthorized / api key not valid") } 500 -> { - logcat(LogPriority.WARN) { "Error fetching JWT token. Cleaned api URL: $apiUrl, Api key is empty: ${apiKey.isEmpty()}" } + logcat( + LogPriority.WARN, + ) { "Error fetching JWT token. API URL: $apiUrl, empty API key: ${apiKey.isEmpty()}" } throw IOException("Error fetching JWT token") } else -> {} @@ -62,12 +66,12 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor // Not sure which one to catch } catch (e: SocketTimeoutException) { logcat(LogPriority.WARN) { - "Could not fetch JWT token. Probably due to connectivity issue or the url '$apiUrl' is not available, skipping" + "Could not fetch JWT token. Probably due to connectivity issue or URL '$apiUrl' not available, skipping" } return null } catch (e: Exception) { logcat(LogPriority.ERROR) { - "Unhandled exception fetching JWT token for url: '$apiUrl'" + "Unhandled exception fetching JWT token for URL: '$apiUrl'" } throw IOException(e) } @@ -129,7 +133,10 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor } } } catch (e: Exception) { - logcat(LogPriority.WARN, e) { "Exception getting latest chapter read. Could not get itemRequest: $requestUrl" } + logcat( + LogPriority.WARN, + e, + ) { "Exception getting latest chapter read. Could not get itemRequest: $requestUrl" } throw e } return 0F @@ -164,8 +171,14 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor } suspend fun updateProgress(track: Track): Track { - val requestUrl = "${getApiFromUrl(track.tracking_url)}/Tachiyomi/mark-chapter-until-as-read?seriesId=${getIdFromUrl(track.tracking_url)}&chapterNumber=${track.last_chapter_read}" - authClient.newCall(POST(requestUrl, body = "{}".toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull()))) + val requestUrl = "${getApiFromUrl( + track.tracking_url, + )}/Tachiyomi/mark-chapter-until-as-read?seriesId=${getIdFromUrl( + track.tracking_url, + )}&chapterNumber=${track.last_chapter_read}" + authClient.newCall( + POST(requestUrl, body = "{}".toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())), + ) .awaitSuccess() return getTrackSearch(track.tracking_url) } 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 d66a4c561..db89bcc11 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 @@ -101,7 +101,10 @@ class MyAnimeListApi( return withIOContext { val url = "$baseApiUrl/manga".toUri().buildUpon() .appendPath(id.toString()) - .appendQueryParameter("fields", "id,title,synopsis,num_chapters,main_picture,status,media_type,start_date") + .appendQueryParameter( + "fields", + "id,title,synopsis,num_chapters,main_picture,status,media_type,start_date", + ) .build() with(json) { authClient.newCall(GET(url.toString())) 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 6beca3851..4f3670929 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 @@ -91,7 +91,9 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker { null } - override fun isTrackFrom(track: DomainTrack, manga: DomainManga, source: Source?): Boolean = source?.let { accept(it) } == true + override fun isTrackFrom(track: DomainTrack, manga: DomainManga, source: Source?): Boolean = source?.let { + accept(it) + } == true override fun migrateTrack(track: DomainTrack, manga: DomainManga, newSource: Source): DomainTrack? = if (accept(newSource)) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt index 08a1cbbb7..3a6a0c14a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt @@ -32,7 +32,9 @@ class AppUpdateChecker { when (result) { is GetApplicationRelease.Result.NewUpdate -> AppUpdateNotifier(context).promptUpdate(result.release) - is GetApplicationRelease.Result.ThirdPartyInstallation -> AppUpdateNotifier(context).promptFdroidUpdate() + is GetApplicationRelease.Result.ThirdPartyInstallation -> AppUpdateNotifier( + context, + ).promptFdroidUpdate() else -> {} } 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 0437103a3..afd1479b4 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 @@ -42,7 +42,12 @@ internal class AppUpdateNotifier(private val context: Context) { val releaseIntent = Intent(Intent.ACTION_VIEW, release.releaseLink.toUri()).run { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP - PendingIntent.getActivity(context, release.hashCode(), this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + PendingIntent.getActivity( + context, + release.hashCode(), + this, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) } with(notificationBuilder) { @@ -143,7 +148,12 @@ 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#how-do-i-update-from-the-f-droid-builds")) + 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/extension/installer/PackageInstallerInstaller.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/PackageInstallerInstaller.kt index fc8d0f46c..dbc1fa50f 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 @@ -101,7 +101,12 @@ class PackageInstallerInstaller(private val service: Service) : Installer(servic } init { - ContextCompat.registerReceiver(service, packageActionReceiver, IntentFilter(INSTALL_ACTION), ContextCompat.RECEIVER_EXPORTED) + ContextCompat.registerReceiver( + service, + packageActionReceiver, + IntentFilter(INSTALL_ACTION), + ContextCompat.RECEIVER_EXPORTED, + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt index a2404fd40..6a3e21860 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt @@ -108,7 +108,9 @@ internal class ExtensionInstallReceiver(private val listener: Listener) : logcat(LogPriority.WARN) { "Package name not found" } return LoadResult.Error } - return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) { ExtensionLoader.loadExtensionFromPkgName(context, pkgName) }.await() + return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) { + ExtensionLoader.loadExtensionFromPkgName(context, pkgName) + }.await() } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt index 9e45460c6..dcbae8b4d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/AndroidSourceManager.kt @@ -36,7 +36,9 @@ class AndroidSourceManager( private val stubSourcesMap = ConcurrentHashMap() - override val catalogueSources: Flow> = sourcesMapFlow.map { it.values.filterIsInstance() } + override val catalogueSources: Flow> = sourcesMapFlow.map { + it.values.filterIsInstance() + } init { scope.launch { 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 37203015a..5e6cbfd98 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 @@ -264,7 +264,9 @@ class BrowseSourceScreenModel( // Choose a category else -> { val preselectedIds = getCategories.await(manga.id).map { it.id } - setDialog(Dialog.ChangeMangaCategory(manga, categories.mapAsCheckboxState { it.id in preselectedIds })) + setDialog( + Dialog.ChangeMangaCategory(manga, categories.mapAsCheckboxState { it.id in preselectedIds }), + ) } } } @@ -314,7 +316,10 @@ class BrowseSourceScreenModel( sealed class Listing(open val query: String?, open val filters: FilterList) { data object Popular : Listing(query = GetRemoteManga.QUERY_POPULAR, filters = FilterList()) data object Latest : Listing(query = GetRemoteManga.QUERY_LATEST, filters = FilterList()) - data class Search(override val query: String?, override val filters: FilterList) : Listing(query = query, filters = filters) + data class Search( + override val query: String?, + override val filters: FilterList, + ) : Listing(query = query, filters = filters) companion object { fun valueOf(query: String?): Listing { 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 fabfaa4b0..0bc2d8b5d 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 @@ -543,7 +543,8 @@ class LibraryScreenModel( } fun getColumnsPreferenceForCurrentOrientation(isLandscape: Boolean): PreferenceMutableState { - return (if (isLandscape) libraryPreferences.landscapeColumns() else libraryPreferences.portraitColumns()).asState(screenModelScope) + return (if (isLandscape) libraryPreferences.landscapeColumns() else libraryPreferences.portraitColumns()) + .asState(screenModelScope) } suspend fun getRandomLibraryItemForCurrentCategory(): LibraryItem? { 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 5469a11a8..aff6a2fdd 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 @@ -178,7 +178,9 @@ object LibraryTab : Tab { scope.launchIO { val chapter = screenModel.getNextUnreadChapter(it.manga) if (chapter != null) { - context.startActivity(ReaderActivity.newIntent(context, chapter.mangaId, chapter.id)) + context.startActivity( + ReaderActivity.newIntent(context, chapter.mangaId, chapter.id), + ) } else { snackbarHostState.showSnackbar(context.getString(R.string.no_next_chapter)) } 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 a7b3b9ce4..51ee88cf1 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 @@ -388,7 +388,11 @@ class MainActivity : BaseActivity() { private fun handleIntentAction(intent: Intent, navigator: Navigator): Boolean { val notificationId = intent.getIntExtra("notificationId", -1) if (notificationId > -1) { - NotificationReceiver.dismissNotification(applicationContext, notificationId, intent.getIntExtra("groupId", 0)) + NotificationReceiver.dismissNotification( + applicationContext, + notificationId, + intent.getIntExtra("groupId", 0), + ) } val tabToOpen = when (intent.action) { 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 f16767a49..a4504e237 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 @@ -112,8 +112,20 @@ class MangaScreen( screenModel.toggleFavorite() haptic.performHapticFeedback(HapticFeedbackType.LongPress) }, - onWebViewClicked = { openMangaInWebView(navigator, screenModel.manga, screenModel.source) }.takeIf { isHttpSource }, - onWebViewLongClicked = { copyMangaUrl(context, screenModel.manga, screenModel.source) }.takeIf { isHttpSource }, + onWebViewClicked = { + openMangaInWebView( + navigator, + screenModel.manga, + screenModel.source, + ) + }.takeIf { isHttpSource }, + onWebViewLongClicked = { + copyMangaUrl( + context, + screenModel.manga, + screenModel.source, + ) + }.takeIf { isHttpSource }, onTrackingClicked = screenModel::showTrackDialog.takeIf { successState.trackingAvailable }, onTagSearch = { scope.launch { performGenreSearch(navigator, it, screenModel.source!!) } }, onFilterButtonClicked = screenModel::showSettingsDialog, @@ -124,8 +136,12 @@ class MangaScreen( onShareClicked = { shareManga(context, screenModel.manga, screenModel.source) }.takeIf { isHttpSource }, onDownloadActionClicked = screenModel::runDownloadAction.takeIf { !successState.source.isLocalOrStub() }, onEditCategoryClicked = screenModel::showChangeCategoryDialog.takeIf { successState.manga.favorite }, - onEditFetchIntervalClicked = screenModel::showSetFetchIntervalDialog.takeIf { screenModel.isUpdateIntervalEnabled && successState.manga.favorite }, - onMigrateClicked = { navigator.push(MigrateSearchScreen(successState.manga.id)) }.takeIf { successState.manga.favorite }, + onEditFetchIntervalClicked = screenModel::showSetFetchIntervalDialog.takeIf { + screenModel.isUpdateIntervalEnabled && successState.manga.favorite + }, + onMigrateClicked = { + navigator.push(MigrateSearchScreen(successState.manga.id)) + }.takeIf { successState.manga.favorite }, onMultiBookmarkClicked = screenModel::bookmarkChapters, onMultiMarkAsReadClicked = screenModel::markChaptersRead, onMarkPreviousAsReadClicked = screenModel::markPreviousChapterRead, 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 4b3cbf0d8..0fae11b49 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 @@ -160,8 +160,18 @@ class ReaderViewModel @JvmOverloads constructor( readerPreferences.skipFiltered().get() -> { (manga.unreadFilterRaw == Manga.CHAPTER_SHOW_READ && !it.read) || (manga.unreadFilterRaw == Manga.CHAPTER_SHOW_UNREAD && it.read) || - (manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_DOWNLOADED && !downloadManager.isChapterDownloaded(it.name, it.scanlator, manga.title, manga.source)) || - (manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_NOT_DOWNLOADED && downloadManager.isChapterDownloaded(it.name, it.scanlator, manga.title, manga.source)) || + ( + manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_DOWNLOADED && + !downloadManager.isChapterDownloaded( + it.name, it.scanlator, manga.title, manga.source, + ) + ) || + ( + manga.downloadedFilterRaw == Manga.CHAPTER_SHOW_NOT_DOWNLOADED && + downloadManager.isChapterDownloaded( + it.name, it.scanlator, manga.title, manga.source, + ) + ) || (manga.bookmarkedFilterRaw == Manga.CHAPTER_SHOW_BOOKMARKED && !it.bookmark) || (manga.bookmarkedFilterRaw == Manga.CHAPTER_SHOW_NOT_BOOKMARKED && it.bookmark) } @@ -759,7 +769,13 @@ class ReaderViewModel @JvmOverloads constructor( val filename = generateFilename(manga, page) // Pictures directory. - val relativePath = if (readerPreferences.folderPerManga().get()) DiskUtil.buildValidFilename(manga.title) else "" + val relativePath = if (readerPreferences.folderPerManga().get()) { + DiskUtil.buildValidFilename( + manga.title, + ) + } else { + "" + } // Copy file in background. viewModelScope.launchNonCancellable { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt index d015a29b7..897d13755 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt @@ -75,7 +75,13 @@ class ChapterLoader( */ private fun getPageLoader(chapter: ReaderChapter): PageLoader { val dbChapter = chapter.chapter - val isDownloaded = downloadManager.isChapterDownloaded(dbChapter.name, dbChapter.scanlator, manga.title, manga.source, skipCache = true) + val isDownloaded = downloadManager.isChapterDownloaded( + dbChapter.name, + dbChapter.scanlator, + manga.title, + manga.source, + skipCache = true, + ) return when { isDownloaded -> DownloadPageLoader(chapter, manga, source, downloadManager, downloadProvider) source is LocalSource -> source.getFormat(chapter.chapter).let { format -> diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt index 3650038f5..c2edb39e9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt @@ -5,14 +5,54 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import eu.kanade.tachiyomi.R -enum class OrientationType(val flag: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int) { - DEFAULT(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.label_default, R.drawable.ic_screen_rotation_24dp, 0x00000000), - FREE(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.rotation_free, R.drawable.ic_screen_rotation_24dp, 0x00000008), - PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, R.string.rotation_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000010), - LANDSCAPE(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, R.string.rotation_landscape, R.drawable.ic_stay_current_landscape_24dp, 0x00000018), - LOCKED_PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, R.string.rotation_force_portrait, R.drawable.ic_screen_lock_portrait_24dp, 0x00000020), - LOCKED_LANDSCAPE(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, R.string.rotation_force_landscape, R.drawable.ic_screen_lock_landscape_24dp, 0x00000028), - REVERSE_PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, R.string.rotation_reverse_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000030), +enum class OrientationType( + val flag: Int, + @StringRes val stringRes: Int, + @DrawableRes val iconRes: Int, + val flagValue: Int, +) { + DEFAULT( + ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, + R.string.label_default, + R.drawable.ic_screen_rotation_24dp, + 0x00000000, + ), + FREE( + ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, + R.string.rotation_free, + R.drawable.ic_screen_rotation_24dp, + 0x00000008, + ), + PORTRAIT( + ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, + R.string.rotation_portrait, + R.drawable.ic_stay_current_portrait_24dp, + 0x00000010, + ), + LANDSCAPE( + ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, + R.string.rotation_landscape, + R.drawable.ic_stay_current_landscape_24dp, + 0x00000018, + ), + LOCKED_PORTRAIT( + ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, + R.string.rotation_force_portrait, + R.drawable.ic_screen_lock_portrait_24dp, + 0x00000020, + ), + LOCKED_LANDSCAPE( + ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, + R.string.rotation_force_landscape, + R.drawable.ic_screen_lock_landscape_24dp, + 0x00000028, + ), + REVERSE_PORTRAIT( + ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, + R.string.rotation_reverse_portrait, + R.drawable.ic_stay_current_portrait_24dp, + 0x00000030, + ), ; companion object { 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 72f2436f4..5b2314916 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 @@ -30,9 +30,15 @@ class ReaderPreferences( fun keepScreenOn() = preferenceStore.getBoolean("pref_keep_screen_on_key", true) - fun defaultReadingMode() = preferenceStore.getInt("pref_default_reading_mode_key", ReadingModeType.RIGHT_TO_LEFT.flagValue) + fun defaultReadingMode() = preferenceStore.getInt( + "pref_default_reading_mode_key", + ReadingModeType.RIGHT_TO_LEFT.flagValue, + ) - fun defaultOrientationType() = preferenceStore.getInt("pref_default_orientation_type_key", OrientationType.FREE.flagValue) + fun defaultOrientationType() = preferenceStore.getInt( + "pref_default_orientation_type_key", + OrientationType.FREE.flagValue, + ) fun webtoonDoubleTapZoomEnabled() = preferenceStore.getBoolean("pref_enable_double_tap_zoom_webtoon", true) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt index 2bce0735b..4d5974ee5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt @@ -10,7 +10,11 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer -enum class ReadingModeType(@StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int) { +enum class ReadingModeType( + @StringRes val stringRes: Int, + @DrawableRes val iconRes: Int, + val flagValue: Int, +) { DEFAULT(R.string.label_default, R.drawable.ic_reader_default_24dp, 0x00000000), LEFT_TO_RIGHT(R.string.left_to_right_viewer, R.drawable.ic_reader_ltr_24dp, 0x00000001), RIGHT_TO_LEFT(R.string.right_to_left_viewer, R.drawable.ic_reader_rtl_24dp, 0x00000002), 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 78a44dd23..9aef16026 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 @@ -87,7 +87,9 @@ object UpdatesTab : Tab { LaunchedEffect(Unit) { screenModel.events.collectLatest { event -> when (event) { - Event.InternalError -> screenModel.snackbarHostState.showSnackbar(context.getString(R.string.internal_error)) + Event.InternalError -> screenModel.snackbarHostState.showSnackbar( + context.getString(R.string.internal_error), + ) is Event.LibraryUpdateTriggered -> { val msg = if (event.started) { R.string.updating_library diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt index 94a65ddcd..3c0fab2ab 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt @@ -36,9 +36,17 @@ fun File.copyAndSetReadOnlyTo(target: File, overwrite: Boolean = false, bufferSi if (target.exists()) { if (!overwrite) { - throw FileAlreadyExistsException(file = this, other = target, reason = "The destination file already exists.") + throw FileAlreadyExistsException( + file = this, + other = target, + reason = "The destination file already exists.", + ) } else if (!target.delete()) { - throw FileAlreadyExistsException(file = this, other = target, reason = "Tried to overwrite the destination, but failed to delete it.") + throw FileAlreadyExistsException( + file = this, + other = target, + reason = "Tried to overwrite the destination, but failed to delete it.", + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt index c9924e297..7917c6db3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt @@ -59,7 +59,9 @@ fun Context.copyToClipboard(label: String, content: String) { * @param permission the permission to check. * @return true if it has permissions. */ -fun Context.hasPermission(permission: String) = PermissionChecker.checkSelfPermission(this, permission) == PermissionChecker.PERMISSION_GRANTED +fun Context.hasPermission( + permission: String, +) = PermissionChecker.checkSelfPermission(this, permission) == PermissionChecker.PERMISSION_GRANTED val Context.powerManager: PowerManager get() = getSystemService()!! @@ -105,7 +107,10 @@ fun Context.openInBrowser(uri: Uri, forceDefaultBrowser: Boolean = false) { private fun Context.defaultBrowserPackageName(): String? { val browserIntent = Intent(Intent.ACTION_VIEW, "http://".toUri()) val resolveInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - packageManager.resolveActivity(browserIntent, PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())) + packageManager.resolveActivity( + browserIntent, + PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong()), + ) } else { packageManager.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/NotificationExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/NotificationExtensions.kt index 5a37d6615..8038f6115 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/NotificationExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/NotificationExtensions.kt @@ -49,7 +49,10 @@ fun Context.cancelNotification(id: Int) { * @param block the function that will execute inside the builder. * @return a notification to be displayed or updated. */ -fun Context.notificationBuilder(channelId: String, block: (NotificationCompat.Builder.() -> Unit)? = null): NotificationCompat.Builder { +fun Context.notificationBuilder( + channelId: String, + block: (NotificationCompat.Builder.() -> Unit)? = null, +): NotificationCompat.Builder { val builder = NotificationCompat.Builder(this, channelId) .setColor(getColor(R.color.accent_blue)) if (block != null) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt index d7be9f9fe..60d357a53 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt @@ -91,6 +91,7 @@ fun View?.isVisibleOnScreen(): Boolean { } val actualPosition = Rect() this.getGlobalVisibleRect(actualPosition) - val screen = Rect(0, 0, Resources.getSystem().displayMetrics.widthPixels, Resources.getSystem().displayMetrics.heightPixels) + val screen = + Rect(0, 0, Resources.getSystem().displayMetrics.widthPixels, Resources.getSystem().displayMetrics.heightPixels) return actualPosition.intersect(screen) } diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/WebViewInterceptor.kt b/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/WebViewInterceptor.kt index c71deaf3e..ff1ca3fac 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/WebViewInterceptor.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/WebViewInterceptor.kt @@ -89,7 +89,8 @@ abstract class WebViewInterceptor( } } -// Based on [IsRequestHeaderSafe] in https://source.chromium.org/chromium/chromium/src/+/main:services/network/public/cpp/header_util.cc +// Based on [IsRequestHeaderSafe] in +// https://source.chromium.org/chromium/chromium/src/+/main:services/network/public/cpp/header_util.cc private fun isRequestHeaderSafe(_name: String, _value: String): Boolean { val name = _name.lowercase(Locale.ENGLISH) val value = _value.lowercase(Locale.ENGLISH) @@ -97,4 +98,6 @@ private fun isRequestHeaderSafe(_name: String, _value: String): Boolean { if (name == "connection" && value == "upgrade") return false return true } -private val unsafeHeaderNames = listOf("content-length", "host", "trailer", "te", "upgrade", "cookie2", "keep-alive", "transfer-encoding", "set-cookie") +private val unsafeHeaderNames = listOf( + "content-length", "host", "trailer", "te", "upgrade", "cookie2", "keep-alive", "transfer-encoding", "set-cookie", +) 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 62a0d347a..b6cbc45e6 100644 --- a/core/src/main/java/tachiyomi/core/util/system/ImageUtil.kt +++ b/core/src/main/java/tachiyomi/core/util/system/ImageUtil.kt @@ -271,7 +271,9 @@ object ImageUtil { } } - private fun splitImageName(filenamePrefix: String, index: Int) = "${filenamePrefix}__${"%03d".format(index + 1)}.jpg" + private fun splitImageName(filenamePrefix: String, index: Int) = "${filenamePrefix}__${"%03d".format( + index + 1, + )}.jpg" private val BitmapFactory.Options.splitData get(): List { @@ -356,10 +358,12 @@ object ImageUtil { val botLeftIsDark = botLeftPixel.isDark() val botRightIsDark = botRightPixel.isDark() - var darkBG = (topLeftIsDark && (botLeftIsDark || botRightIsDark || topRightIsDark || midLeftIsDark || topMidIsDark)) || - (topRightIsDark && (botRightIsDark || botLeftIsDark || midRightIsDark || topMidIsDark)) + var darkBG = + (topLeftIsDark && (botLeftIsDark || botRightIsDark || topRightIsDark || midLeftIsDark || topMidIsDark)) || + (topRightIsDark && (botRightIsDark || botLeftIsDark || midRightIsDark || topMidIsDark)) - val topAndBotPixels = listOf(topLeftPixel, topCenterPixel, topRightPixel, botRightPixel, bottomCenterPixel, botLeftPixel) + val topAndBotPixels = + listOf(topLeftPixel, topCenterPixel, topRightPixel, botRightPixel, bottomCenterPixel, botLeftPixel) val isNotWhiteAndCloseTo = topAndBotPixels.mapIndexed { index, color -> val other = topAndBotPixels[(index + 1) % topAndBotPixels.size] !color.isWhite() && color.isCloseTo(other) @@ -504,10 +508,16 @@ object ImageUtil { darkBG -> { return ColorDrawable(blackColor) } - topIsBlackStreak || (topCornersIsDark && topOffsetCornersIsDark && (topMidIsDark || overallBlackPixels > 9)) -> { + topIsBlackStreak || ( + topCornersIsDark && topOffsetCornersIsDark && + (topMidIsDark || overallBlackPixels > 9) + ) -> { intArrayOf(blackColor, blackColor, whiteColor, whiteColor) } - bottomIsBlackStreak || (botCornersIsDark && botOffsetCornersIsDark && (bottomCenterPixel.isDark() || overallBlackPixels > 9)) -> { + bottomIsBlackStreak || ( + botCornersIsDark && botOffsetCornersIsDark && + (bottomCenterPixel.isDark() || overallBlackPixels > 9) + ) -> { intArrayOf(whiteColor, whiteColor, blackColor, blackColor) } else -> { diff --git a/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt b/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt index c87ec5cff..adc1d26a0 100644 --- a/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt +++ b/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt @@ -8,9 +8,8 @@ import eu.kanade.tachiyomi.source.model.SManga 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.getSearchManga(currentPage, query, filters) } diff --git a/domain/src/main/java/tachiyomi/domain/chapter/model/ChapterUpdate.kt b/domain/src/main/java/tachiyomi/domain/chapter/model/ChapterUpdate.kt index 58cc88821..33d1d4fba 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/model/ChapterUpdate.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/model/ChapterUpdate.kt @@ -16,5 +16,18 @@ data class ChapterUpdate( ) fun Chapter.toChapterUpdate(): ChapterUpdate { - return ChapterUpdate(id, mangaId, read, bookmark, lastPageRead, dateFetch, sourceOrder, url, name, dateUpload, chapterNumber, scanlator) + return ChapterUpdate( + id, + mangaId, + read, + bookmark, + lastPageRead, + dateFetch, + sourceOrder, + url, + name, + dateUpload, + chapterNumber, + scanlator, + ) } 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 03380180e..83c847820 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 @@ -95,7 +95,10 @@ fun VerticalFastScroller( } val thumbBottomPadding = with(LocalDensity.current) { bottomContentPadding.toPx() } - val heightPx = contentHeight.toFloat() - thumbTopPadding - thumbBottomPadding - listState.layoutInfo.afterContentPadding + val heightPx = contentHeight.toFloat() - + thumbTopPadding - + thumbBottomPadding - + listState.layoutInfo.afterContentPadding val thumbHeightPx = with(LocalDensity.current) { ThumbLength.toPx() } val trackHeightPx = heightPx - thumbHeightPx @@ -261,7 +264,10 @@ fun VerticalGridFastScroller( } val thumbBottomPadding = with(LocalDensity.current) { bottomContentPadding.toPx() } - val heightPx = contentHeight.toFloat() - thumbTopPadding - thumbBottomPadding - state.layoutInfo.afterContentPadding + val heightPx = contentHeight.toFloat() - + thumbTopPadding - + thumbBottomPadding - + state.layoutInfo.afterContentPadding val thumbHeightPx = with(LocalDensity.current) { ThumbLength.toPx() } val trackHeightPx = heightPx - thumbHeightPx diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/util/Scrollbar.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/util/Scrollbar.kt index b842952e8..e0cd0a3e0 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/util/Scrollbar.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/util/Scrollbar.kt @@ -121,7 +121,11 @@ private fun Modifier.drawScrollbar( items .fastFirstOrNull { (it.key as? String)?.startsWith(STICKY_HEADER_KEY_PREFIX)?.not() ?: true }!! .run { - val startPadding = if (reverseDirection) layoutInfo.afterContentPadding else layoutInfo.beforeContentPadding + val startPadding = if (reverseDirection) { + layoutInfo.afterContentPadding + } else { + layoutInfo.beforeContentPadding + } startPadding + ((estimatedItemSize * index - offset) / totalSize * viewportSize) } } 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 63a3b329d..46f8d26e6 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 @@ -70,7 +70,10 @@ fun UpdatesWidget( .padding(horizontal = 3.dp), contentAlignment = Alignment.Center, ) { - val intent = Intent(LocalContext.current, Class.forName(Constants.MAIN_ACTIVITY)).apply { + 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) 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 636d205f2..951b163b6 100644 --- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt +++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt @@ -72,7 +72,13 @@ actual class LocalSource( 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 } + val lastModifiedLimit by lazy { + if (filters === LATEST_FILTERS) { + System.currentTimeMillis() - LATEST_THRESHOLD + } else { + 0L + } + } var mangaDirs = baseDirsFiles // Filter out files that are hidden and is not a folder .filter { it.isDirectory && !it.name.startsWith('.') } From 4f3a0b352397bc6184962e0664d26731ffdd27f8 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 5 Nov 2023 09:08:17 -0500 Subject: [PATCH 51/66] Postpone Android 8 requirement --- .../eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt index 3a6a0c14a..c50524766 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.data.updater import android.content.Context -import android.os.Build import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.util.system.isInstalledFromFDroid import tachiyomi.core.util.lang.withIOContext @@ -13,10 +12,10 @@ class AppUpdateChecker { private val getApplicationRelease: GetApplicationRelease by injectLazy() suspend fun checkForUpdate(context: Context, forceCheck: Boolean = false): GetApplicationRelease.Result { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { - return GetApplicationRelease.Result.OsTooOld - } // Disable app update checks for older Android versions that we're going to drop support for + // if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { + // return GetApplicationRelease.Result.OsTooOld + // } return withIOContext { val result = getApplicationRelease.await( From 953f5fb0253879547a94f88231b36ce81a35b48e Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 5 Nov 2023 09:14:57 -0500 Subject: [PATCH 52/66] Lint fixes --- .../interactor/SyncChaptersWithSource.kt | 4 +++- .../presentation/browse/GlobalSearchScreen.kt | 4 +++- .../browse/components/BrowseSourceToolbar.kt | 6 ++++- .../presentation/category/CategoryScreen.kt | 4 +++- .../category/components/CategoryDialogs.kt | 20 ++++++++++++---- .../kanade/presentation/components/AppBar.kt | 6 ++++- .../library/LibrarySettingsDialog.kt | 12 ++++++++-- .../manga/ChapterSettingsDialog.kt | 3 ++- .../settings/screen/SettingsLibraryScreen.kt | 24 ++++++++++++------- .../settings/screen/SettingsReaderScreen.kt | 24 +++++++++---------- .../settings/screen/SettingsSearchScreen.kt | 6 ++++- .../settings/screen/debug/DebugInfoScreen.kt | 3 ++- .../tachiyomi/data/backup/BackupRestorer.kt | 8 ++++++- .../data/backup/models/BackupChapter.kt | 18 ++++++++++++-- .../data/backup/models/BackupTracking.kt | 15 +++++++++++- .../tachiyomi/data/download/DownloadCache.kt | 5 ++-- .../data/library/LibraryUpdateNotifier.kt | 7 ++++-- .../tachiyomi/data/track/BaseTracker.kt | 6 ++++- .../tachiyomi/data/track/kitsu/KitsuApi.kt | 4 +++- .../data/track/shikimori/ShikimoriApi.kt | 3 ++- .../extension/api/ExtensionGithubApi.kt | 5 +++- .../extension/util/ExtensionInstaller.kt | 5 +++- .../browse/extension/ExtensionsScreenModel.kt | 3 ++- .../tachiyomi/ui/manga/MangaScreenModel.kt | 11 +++++++-- .../tachiyomi/ui/reader/ReaderActivity.kt | 3 ++- .../ui/reader/viewer/ReaderPageImageView.kt | 8 ++++++- .../ui/reader/viewer/pager/PagerViewer.kt | 3 ++- .../tachiyomi/util/lang/DateExtensions.kt | 3 ++- .../util/system/NotificationExtensions.kt | 16 +++++++++++-- 29 files changed, 182 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt index d233406f0..fd878d5f8 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt @@ -116,7 +116,9 @@ class SyncChaptersWithSource( } else { if (shouldUpdateDbChapter.await(dbChapter, chapter)) { val shouldRenameChapter = downloadProvider.isChapterDirNameChanged(dbChapter, chapter) && - downloadManager.isChapterDownloaded(dbChapter.name, dbChapter.scanlator, manga.title, manga.source) + downloadManager.isChapterDownloaded( + dbChapter.name, dbChapter.scanlator, manga.title, manga.source, + ) if (shouldRenameChapter) { downloadManager.renameChapter(source, manga, dbChapter, chapter) diff --git a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt index 4df4179fe..508bffe2d 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt @@ -74,7 +74,9 @@ internal fun GlobalSearchContent( items.forEach { (source, result) -> item(key = source.id) { GlobalSearchResultItem( - title = fromSourceId?.let { "▶ ${source.name}".takeIf { source.id == fromSourceId } } ?: source.name, + title = fromSourceId?.let { + "▶ ${source.name}".takeIf { source.id == fromSourceId } + } ?: source.name, subtitle = LocaleHelper.getDisplayName(source.lang), onClick = { onClickSource(source) }, ) { diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt index ccea144a2..4ee222e22 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt @@ -56,7 +56,11 @@ fun BrowseSourceToolbar( actions = listOfNotNull( AppBar.Action( title = stringResource(R.string.action_display_mode), - icon = if (displayMode == LibraryDisplayMode.List) Icons.Filled.ViewList else Icons.Filled.ViewModule, + icon = if (displayMode == LibraryDisplayMode.List) { + Icons.Filled.ViewList + } else { + Icons.Filled.ViewModule + }, onClick = { selectingDisplayMode = true }, ), if (isLocalSource) { 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 485d3e4ff..7d4327814 100644 --- a/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt @@ -75,7 +75,9 @@ fun CategoryScreen( CategoryContent( categories = state.categories, lazyListState = lazyListState, - paddingValues = paddingValues + topSmallPaddingValues + PaddingValues(horizontal = MaterialTheme.padding.medium), + paddingValues = paddingValues + + topSmallPaddingValues + + PaddingValues(horizontal = MaterialTheme.padding.medium), onClickRename = onClickRename, onClickDelete = onClickDelete, onMoveUp = onClickMoveUp, 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 ad30e4e2d..684fc7dad 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 @@ -74,7 +74,11 @@ fun CategoryCreateDialog( onValueChange = { name = it }, label = { Text(text = stringResource(R.string.name)) }, supportingText = { - val msgRes = if (name.isNotEmpty() && nameAlreadyExists) R.string.error_category_exists else R.string.information_required_plain + val msgRes = if (name.isNotEmpty() && nameAlreadyExists) { + R.string.error_category_exists + } else { + R.string.information_required_plain + } Text(text = stringResource(msgRes)) }, isError = name.isNotEmpty() && nameAlreadyExists, @@ -134,7 +138,11 @@ fun CategoryRenameDialog( }, label = { Text(text = stringResource(R.string.name)) }, supportingText = { - val msgRes = if (valueHasChanged && nameAlreadyExists) R.string.error_category_exists else R.string.information_required_plain + val msgRes = if (valueHasChanged && nameAlreadyExists) { + R.string.error_category_exists + } else { + R.string.information_required_plain + } Text(text = stringResource(msgRes)) }, isError = valueHasChanged && nameAlreadyExists, @@ -257,8 +265,12 @@ fun ChangeCategoryDialog( onClick = { onDismissRequest() onConfirm( - selection.filter { it is CheckboxState.State.Checked || it is CheckboxState.TriState.Include }.map { it.value.id }, - selection.filter { it is CheckboxState.State.None || it is CheckboxState.TriState.None }.map { it.value.id }, + selection + .filter { it is CheckboxState.State.Checked || it is CheckboxState.TriState.Include } + .map { it.value.id }, + selection + .filter { it is CheckboxState.State.None || it is CheckboxState.TriState.None } + .map { it.value.id }, ) }, ) { diff --git a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt index 7ccfae0bd..96278f506 100644 --- a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt +++ b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt @@ -370,7 +370,11 @@ fun SearchToolbar( @Composable fun UpIcon(navigationIcon: ImageVector? = null) { val icon = navigationIcon - ?: if (LocalLayoutDirection.current == LayoutDirection.Ltr) Icons.Outlined.ArrowBack else Icons.Outlined.ArrowForward + ?: if (LocalLayoutDirection.current == LayoutDirection.Ltr) { + Icons.Outlined.ArrowBack + } else { + Icons.Outlined.ArrowForward + } Icon( imageVector = icon, contentDescription = stringResource(R.string.abc_action_bar_up_description), 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 c97740940..4e0bd45d5 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -167,8 +167,16 @@ private fun ColumnScope.SortPage( onClick = { val isTogglingDirection = sortingMode == mode val direction = when { - isTogglingDirection -> if (sortDescending) LibrarySort.Direction.Ascending else LibrarySort.Direction.Descending - else -> if (sortDescending) LibrarySort.Direction.Descending else LibrarySort.Direction.Ascending + isTogglingDirection -> if (sortDescending) { + LibrarySort.Direction.Ascending + } else { + LibrarySort.Direction.Descending + } + else -> if (sortDescending) { + LibrarySort.Direction.Descending + } else { + LibrarySort.Direction.Ascending + } } screenModel.setSort(category, mode, direction) }, diff --git a/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt index dd4b29c72..7370a1449 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt @@ -83,7 +83,8 @@ fun ChapterSettingsDialog( 0 -> { FilterPage( downloadFilter = manga?.downloadedFilter ?: TriState.DISABLED, - onDownloadFilterChanged = onDownloadFilterChanged.takeUnless { manga?.forceDownloaded() == true }, + onDownloadFilterChanged = onDownloadFilterChanged + .takeUnless { manga?.forceDownloaded() == true }, unreadFilter = manga?.unreadFilter ?: TriState.DISABLED, onUnreadFilterChanged = onUnreadFilterChanged, bookmarkedFilter = manga?.bookmarkedFilter ?: TriState.DISABLED, 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 6dc95d6b0..0f978b573 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 @@ -225,20 +225,28 @@ object SettingsLibraryScreen : SearchableSettings { pref = libraryPreferences.swipeToStartAction(), title = stringResource(R.string.pref_chapter_swipe_start), entries = mapOf( - LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.disabled), - LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark), - LibraryPreferences.ChapterSwipeAction.ToggleRead to stringResource(R.string.action_mark_as_read), - LibraryPreferences.ChapterSwipeAction.Download to stringResource(R.string.action_download), + LibraryPreferences.ChapterSwipeAction.Disabled to + stringResource(R.string.disabled), + LibraryPreferences.ChapterSwipeAction.ToggleBookmark to + stringResource(R.string.action_bookmark), + LibraryPreferences.ChapterSwipeAction.ToggleRead to + stringResource(R.string.action_mark_as_read), + LibraryPreferences.ChapterSwipeAction.Download to + stringResource(R.string.action_download), ), ), Preference.PreferenceItem.ListPreference( pref = libraryPreferences.swipeToEndAction(), title = stringResource(R.string.pref_chapter_swipe_end), entries = mapOf( - LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.disabled), - LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark), - LibraryPreferences.ChapterSwipeAction.ToggleRead to stringResource(R.string.action_mark_as_read), - LibraryPreferences.ChapterSwipeAction.Download to stringResource(R.string.action_download), + LibraryPreferences.ChapterSwipeAction.Disabled to + stringResource(R.string.disabled), + LibraryPreferences.ChapterSwipeAction.ToggleBookmark to + stringResource(R.string.action_bookmark), + LibraryPreferences.ChapterSwipeAction.ToggleRead to + stringResource(R.string.action_mark_as_read), + LibraryPreferences.ChapterSwipeAction.Download to + stringResource(R.string.action_download), ), ), ), 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 14e0fd9df..4d975200a 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 @@ -174,12 +174,12 @@ object SettingsReaderScreen : SearchableSettings { Preference.PreferenceItem.ListPreference( pref = readerPreferences.pagerNavInverted(), title = stringResource(R.string.pref_read_with_tapping_inverted), - entries = mapOf( - ReaderPreferences.TappingInvertMode.NONE to stringResource(R.string.none), - ReaderPreferences.TappingInvertMode.HORIZONTAL to stringResource(R.string.tapping_inverted_horizontal), - ReaderPreferences.TappingInvertMode.VERTICAL to stringResource(R.string.tapping_inverted_vertical), - ReaderPreferences.TappingInvertMode.BOTH to stringResource(R.string.tapping_inverted_both), - ), + entries = listOf( + ReaderPreferences.TappingInvertMode.NONE, + ReaderPreferences.TappingInvertMode.HORIZONTAL, + ReaderPreferences.TappingInvertMode.VERTICAL, + ReaderPreferences.TappingInvertMode.BOTH, + ).associateWith { stringResource(it.titleResId) }, enabled = navMode != 5, ), Preference.PreferenceItem.ListPreference( @@ -266,12 +266,12 @@ object SettingsReaderScreen : SearchableSettings { Preference.PreferenceItem.ListPreference( pref = readerPreferences.webtoonNavInverted(), title = stringResource(R.string.pref_read_with_tapping_inverted), - entries = mapOf( - ReaderPreferences.TappingInvertMode.NONE to stringResource(R.string.none), - ReaderPreferences.TappingInvertMode.HORIZONTAL to stringResource(R.string.tapping_inverted_horizontal), - ReaderPreferences.TappingInvertMode.VERTICAL to stringResource(R.string.tapping_inverted_vertical), - ReaderPreferences.TappingInvertMode.BOTH to stringResource(R.string.tapping_inverted_both), - ), + entries = listOf( + ReaderPreferences.TappingInvertMode.NONE, + ReaderPreferences.TappingInvertMode.HORIZONTAL, + ReaderPreferences.TappingInvertMode.VERTICAL, + ReaderPreferences.TappingInvertMode.BOTH, + ).associateWith { stringResource(it.titleResId) }, enabled = navMode != 5, ), Preference.PreferenceItem.SliderPreference( diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt index b67ac38c5..adf184a9f 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt @@ -202,7 +202,11 @@ private fun SearchResult( SearchResultItem( route = settingsData.route, title = p.title, - breadcrumbs = getLocalizedBreadcrumb(path = settingsData.title, node = categoryTitle, isLtr = isLtr), + breadcrumbs = getLocalizedBreadcrumb( + path = settingsData.title, + node = categoryTitle, + isLtr = isLtr, + ), highlightKey = p.title, ) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt index 0e3bcde93..c37db1c6c 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/DebugInfoScreen.kt @@ -78,7 +78,8 @@ class DebugInfoScreen : Screen() { value = when (result) { ProfileVerifier.CompilationStatus.RESULT_CODE_NO_PROFILE -> "No profile installed" ProfileVerifier.CompilationStatus.RESULT_CODE_COMPILED_WITH_PROFILE -> "Compiled" - ProfileVerifier.CompilationStatus.RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING -> "Compiled non-matching" + ProfileVerifier.CompilationStatus.RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING -> + "Compiled non-matching" ProfileVerifier.CompilationStatus.RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ, ProfileVerifier.CompilationStatus.RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE, ProfileVerifier.CompilationStatus.RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST, 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 54c153b33..f78cdceca 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 @@ -446,7 +446,13 @@ class BackupRestorer( return backupManga } - private suspend fun restoreExtras(manga: Manga, categories: List, history: List, tracks: List, backupCategories: List) { + private suspend fun restoreExtras( + manga: Manga, + categories: List, + history: List, + tracks: List, + backupCategories: List, + ) { restoreCategories(manga, categories, backupCategories) restoreHistory(history) restoreTracking(manga, tracks) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt index 6d8cba4e2..567ca372c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt @@ -39,7 +39,21 @@ data class BackupChapter( } } -val backupChapterMapper = { _: Long, _: Long, url: String, name: String, scanlator: String?, read: Boolean, bookmark: Boolean, lastPageRead: Long, chapterNumber: Double, source_order: Long, dateFetch: Long, dateUpload: Long, lastModifiedAt: Long -> +val backupChapterMapper = { + _: Long, + _: Long, + url: String, + name: String, + scanlator: String?, + read: Boolean, + bookmark: Boolean, + lastPageRead: Long, + chapterNumber: Double, + sourceOrder: Long, + dateFetch: Long, + dateUpload: Long, + lastModifiedAt: Long, + -> BackupChapter( url = url, name = name, @@ -50,7 +64,7 @@ val backupChapterMapper = { _: Long, _: Long, url: String, name: String, scanlat lastPageRead = lastPageRead, dateFetch = dateFetch, dateUpload = dateUpload, - sourceOrder = source_order, + sourceOrder = sourceOrder, lastModifiedAt = lastModifiedAt, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt index 0cbbf51a0..b45b30ca2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt @@ -54,7 +54,20 @@ data class BackupTracking( } val backupTrackMapper = { - _: Long, _: Long, syncId: Long, mediaId: Long, libraryId: Long?, title: String, lastChapterRead: Double, totalChapters: Long, status: Long, score: Double, remoteUrl: String, startDate: Long, finishDate: Long -> + _: Long, + _: Long, + syncId: Long, + mediaId: Long, + libraryId: Long?, + title: String, + lastChapterRead: Double, + totalChapters: Long, + status: Long, + score: Double, + remoteUrl: String, + startDate: Long, + finishDate: Long, + -> BackupTracking( syncId = syncId.toInt(), mediaId = mediaId, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt index 018a55f1b..ff11da580 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt @@ -358,9 +358,8 @@ class DownloadCache( // Folder of images it.isDirectory -> it.name // CBZ files - it.isFile && it.name?.endsWith(".cbz") == true -> it.name!!.substringBeforeLast( - ".cbz", - ) + it.isFile && it.name?.endsWith(".cbz") == true -> + it.name!!.substringBeforeLast(".cbz") // Anything else is irrelevant else -> null } 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 cc3a0d8d3..e590d7f4f 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 @@ -336,7 +336,9 @@ class LibraryUpdateNotifier(private val context: Context) { if (shouldTruncate) { // "Chapters 1, 2.5, 3, 4, 5 and 10 more" val remaining = displayableChapterNumbers.size - NOTIF_MAX_CHAPTERS - val joinedChapterNumbers = displayableChapterNumbers.take(NOTIF_MAX_CHAPTERS).joinToString(", ") + val joinedChapterNumbers = displayableChapterNumbers + .take(NOTIF_MAX_CHAPTERS) + .joinToString(", ") context.resources.getQuantityString( R.plurals.notification_chapters_multiple_and_more, remaining, @@ -371,7 +373,8 @@ class LibraryUpdateNotifier(private val context: Context) { } companion object { - const val HELP_WARNING_URL = "https://tachiyomi.org/docs/faq/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" } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt index 277638bc1..5a57e2563 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt @@ -79,7 +79,11 @@ abstract class BaseTracker( } override suspend fun setRemoteLastChapterRead(track: Track, chapterNumber: Int) { - if (track.last_chapter_read == 0f && track.last_chapter_read < chapterNumber && track.status != getRereadingStatus()) { + if ( + track.last_chapter_read == 0f && + track.last_chapter_read < chapterNumber && + track.status != getRereadingStatus() + ) { track.status = getReadingStatus() } track.last_chapter_read = chapterNumber.toFloat() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt index 1764c0290..2d54b266b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt @@ -278,7 +278,9 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) "https://AWQO5J657S-dsn.algolia.net/1/indexes/production_media/query/" private const val algoliaAppId = "AWQO5J657S" private const val algoliaFilter = - "&facetFilters=%5B%22kind%3Amanga%22%5D&attributesToRetrieve=%5B%22synopsis%22%2C%22canonicalTitle%22%2C%22chapterCount%22%2C%22posterImage%22%2C%22startDate%22%2C%22subtype%22%2C%22endDate%22%2C%20%22id%22%5D" + "&facetFilters=%5B%22kind%3Amanga%22%5D&attributesToRetrieve=" + + "%5B%22synopsis%22%2C%22canonicalTitle%22%2C%22chapterCount%22%2C%22" + + "posterImage%22%2C%22startDate%22%2C%22subtype%22%2C%22endDate%22%2C%20%22id%22%5D" fun mangaUrl(remoteId: Long): String { return baseMangaUrl + remoteId 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 8e9033607..8ae22f3c9 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 @@ -59,7 +59,8 @@ class ShikimoriApi( ).awaitSuccess() .parseAs() .let { - track.library_id = it["id"]!!.jsonPrimitive.long // save id of the entry for possible future delete request + // save id of the entry for possible future delete request + track.library_id = it["id"]!!.jsonPrimitive.long } track } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt index 82d10cb76..f2a1c25ed 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt @@ -71,7 +71,10 @@ internal class ExtensionGithubApi { } } - suspend fun checkForUpdates(context: Context, fromAvailableExtensionList: Boolean = false): List? { + suspend fun checkForUpdates( + context: Context, + fromAvailableExtensionList: Boolean = false, + ): List? { // Limit checks to once a day at most if (!fromAvailableExtensionList && Date().time < lastExtCheck.get() + 1.days.inWholeMilliseconds) { return null 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 01f212d8e..ff384e56f 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 @@ -133,7 +133,10 @@ internal class ExtensionInstaller(private val context: Context) { emit(downloadStatus) // Stop polling when the download fails or finishes - if (downloadStatus == DownloadManager.STATUS_SUCCESSFUL || downloadStatus == DownloadManager.STATUS_FAILED) { + if ( + downloadStatus == DownloadManager.STATUS_SUCCESSFUL || + downloadStatus == DownloadManager.STATUS_FAILED + ) { return@flow } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt index 7bef3a4c1..04a2b408d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt @@ -100,7 +100,8 @@ class ExtensionsScreenModel( .groupBy { it.lang } .toSortedMap(LocaleHelper.comparator) .map { (lang, exts) -> - ExtensionUiModel.Header.Text(LocaleHelper.getSourceDisplayName(lang, context)) to exts.map(extensionMapper(downloads)) + ExtensionUiModel.Header.Text(LocaleHelper.getSourceDisplayName(lang, context)) to + exts.map(extensionMapper(downloads)) } if (languagesWithExtensions.isNotEmpty()) { itemsGroups.putAll(languagesWithExtensions) 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 37c4dab9b..004414bc5 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 @@ -133,7 +133,8 @@ class MangaScreenModel( val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get())) private val skipFiltered by readerPreferences.skipFiltered().asState(screenModelScope) - val isUpdateIntervalEnabled = LibraryPreferences.MANGA_OUTSIDE_RELEASE_PERIOD in libraryPreferences.autoUpdateMangaRestrictions().get() + val isUpdateIntervalEnabled = + LibraryPreferences.MANGA_OUTSIDE_RELEASE_PERIOD in libraryPreferences.autoUpdateMangaRestrictions().get() private val selectedPositions: Array = arrayOf(-1, -1) // first and last selected index in list private val selectedChapterIds: HashSet = HashSet() @@ -744,7 +745,13 @@ class MangaScreenModel( screenModelScope.launchNonCancellable { val manga = successState?.manga ?: return@launchNonCancellable val categories = getCategories.await(manga.id).map { it.id } - if (chapters.isEmpty() || !manga.shouldDownloadNewChapters(categories, downloadPreferences)) return@launchNonCancellable + if ( + chapters.isEmpty() || + !manga.shouldDownloadNewChapters(categories, downloadPreferences) + ) { + return@launchNonCancellable + } + downloadChapters(chapters) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 9580af393..a9428213f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -470,7 +470,8 @@ class ReaderActivity : BaseActivity() { } else { if (readerPreferences.fullscreen().get()) { windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) - windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + windowInsetsController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt index 02d4cce9e..c60e404e7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt @@ -110,7 +110,13 @@ open class ReaderPageImageView @JvmOverloads constructor( } private fun SubsamplingScaleImageView.landscapeZoom(forward: Boolean) { - if (config != null && config!!.landscapeZoom && config!!.minimumScaleType == SCALE_TYPE_CENTER_INSIDE && sWidth > sHeight && scale == minScale) { + if ( + config != null && + config!!.landscapeZoom && + config!!.minimumScaleType == SCALE_TYPE_CENTER_INSIDE && + sWidth > sHeight && + scale == minScale + ) { handler?.postDelayed(500) { val point = when (config!!.zoomStartPosition) { ZoomStartPosition.LEFT -> if (forward) PointF(0F, 0F) else PointF(sWidth.toFloat(), 0F) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt index 71ec13ffb..573ba1246 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt @@ -268,7 +268,8 @@ abstract class PagerViewer(val activity: ReaderActivity) : Viewer { * Sets the active [chapters] on this pager. */ private fun setChaptersInternal(chapters: ViewerChapters) { - val forceTransition = config.alwaysShowChapterTransition || adapter.items.getOrNull(pager.currentItem) is ChapterTransition + val forceTransition = config.alwaysShowChapterTransition || + adapter.items.getOrNull(pager.currentItem) is ChapterTransition adapter.setChapters(chapters, forceTransition) // Layout the pager once a chapter is being set 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 e2f683685..797890ef5 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 @@ -56,7 +56,8 @@ fun Date.toRelativeString( return dateFormat.format(this) } val now = Date() - val difference = now.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY) - this.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY) + 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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/NotificationExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/NotificationExtensions.kt index 8038f6115..7a72a5173 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/NotificationExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/NotificationExtensions.kt @@ -23,7 +23,13 @@ fun Context.notify(id: Int, channelId: String, block: (NotificationCompat.Builde } fun Context.notify(id: Int, notification: Notification) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && PermissionChecker.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PermissionChecker.PERMISSION_GRANTED) { + if ( + Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && + PermissionChecker.checkSelfPermission( + this, + Manifest.permission.POST_NOTIFICATIONS, + ) != PermissionChecker.PERMISSION_GRANTED + ) { return } @@ -31,7 +37,13 @@ fun Context.notify(id: Int, notification: Notification) { } fun Context.notify(notificationWithIdAndTags: List) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && PermissionChecker.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PermissionChecker.PERMISSION_GRANTED) { + if ( + Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && + PermissionChecker.checkSelfPermission( + this, + Manifest.permission.POST_NOTIFICATIONS, + ) != PermissionChecker.PERMISSION_GRANTED + ) { return } From 5f34539525f93a92ca80f3b1fb9e71953b6758a1 Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Sun, 5 Nov 2023 21:15:51 +0700 Subject: [PATCH 53/66] MangaScreen: Adjust "missing chapter count" item list styling (#10105) Text style to labelMedium and set secondary alpha to the whole row --- .../kanade/presentation/manga/MangaScreen.kt | 28 +--------- .../components/MissingChapterCountListItem.kt | 52 +++++++++++++++++++ 2 files changed, 54 insertions(+), 26 deletions(-) create mode 100644 app/src/main/java/eu/kanade/presentation/manga/components/MissingChapterCountListItem.kt 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 38e8b7814..698db525b 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -5,11 +5,9 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.asPaddingValues @@ -28,9 +26,7 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.PlayArrow -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text @@ -48,7 +44,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.util.fastAll import androidx.compose.ui.util.fastAny @@ -62,6 +57,7 @@ import eu.kanade.presentation.manga.components.MangaBottomActionMenu import eu.kanade.presentation.manga.components.MangaChapterListItem import eu.kanade.presentation.manga.components.MangaInfoBox import eu.kanade.presentation.manga.components.MangaToolbar +import eu.kanade.presentation.manga.components.MissingChapterCountListItem import eu.kanade.presentation.util.formatChapterNumber import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.download.model.Download @@ -80,10 +76,8 @@ import tachiyomi.presentation.core.components.VerticalFastScroller import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton import tachiyomi.presentation.core.components.material.PullRefresh import tachiyomi.presentation.core.components.material.Scaffold -import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.util.isScrolledToEnd import tachiyomi.presentation.core.util.isScrollingUp -import tachiyomi.presentation.core.util.secondaryItemAlpha import java.text.DateFormat import java.util.Date @@ -789,25 +783,7 @@ private fun LazyListScope.sharedChapterItems( when (item) { is ChapterList.MissingCount -> { - Row( - modifier = Modifier.padding( - horizontal = MaterialTheme.padding.medium, - vertical = MaterialTheme.padding.small, - ), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.medium), - ) { - HorizontalDivider(modifier = Modifier.weight(1f)) - Text( - text = pluralStringResource( - id = R.plurals.missing_chapters, - count = item.count, - item.count, - ), - modifier = Modifier.secondaryItemAlpha(), - ) - HorizontalDivider(modifier = Modifier.weight(1f)) - } + MissingChapterCountListItem(count = item.count) } is ChapterList.Item -> { MangaChapterListItem( diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MissingChapterCountListItem.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MissingChapterCountListItem.kt new file mode 100644 index 000000000..deebaf8e3 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MissingChapterCountListItem.kt @@ -0,0 +1,52 @@ +package eu.kanade.presentation.manga.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.pluralStringResource +import androidx.compose.ui.tooling.preview.PreviewLightDark +import eu.kanade.presentation.theme.TachiyomiTheme +import eu.kanade.tachiyomi.R +import tachiyomi.presentation.core.components.material.padding +import tachiyomi.presentation.core.util.secondaryItemAlpha + +@Composable +fun MissingChapterCountListItem( + count: Int, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier + .padding( + horizontal = MaterialTheme.padding.medium, + vertical = MaterialTheme.padding.small, + ) + .secondaryItemAlpha(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.medium), + ) { + HorizontalDivider(modifier = Modifier.weight(1f)) + Text( + text = pluralStringResource(id = R.plurals.missing_chapters, count = count, count), + style = MaterialTheme.typography.labelMedium, + ) + HorizontalDivider(modifier = Modifier.weight(1f)) + } +} + +@PreviewLightDark +@Composable +private fun Preview() { + TachiyomiTheme { + Surface { + MissingChapterCountListItem(count = 42) + } + } +} From 4502902fb0df21f637c905dc5c4c36625dedc710 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 5 Nov 2023 10:01:19 -0500 Subject: [PATCH 54/66] Clean up reading mode / orientation enum classes Categorizing the reading modes so we can implement a better selection UI. --- .../manga/interactor/SetMangaViewerFlags.kt | 8 +-- .../eu/kanade/domain/manga/model/Manga.kt | 12 ++-- .../settings/screen/SettingsReaderScreen.kt | 8 +-- ...ctDialog.kt => OrientationSelectDialog.kt} | 20 +++---- .../reader/ReadingModeSelectDialog.kt | 14 ++--- .../reader/appbars/BottomReaderBar.kt | 14 ++--- .../reader/appbars/ReaderAppBars.kt | 14 ++--- .../reader/settings/ReadingModePage.kt | 34 +++++------ .../java/eu/kanade/tachiyomi/Migrations.kt | 14 ++--- .../data/backup/models/BackupManga.kt | 4 +- .../tachiyomi/ui/reader/ReaderActivity.kt | 28 ++++----- .../tachiyomi/ui/reader/ReaderViewModel.kt | 34 +++++------ ...rientationType.kt => ReaderOrientation.kt} | 4 +- .../ui/reader/setting/ReaderPreferences.kt | 4 +- .../setting/ReaderSettingsScreenModel.kt | 4 +- .../{ReadingModeType.kt => ReadingMode.kt} | 58 ++++++++++++++++--- 16 files changed, 156 insertions(+), 118 deletions(-) rename app/src/main/java/eu/kanade/presentation/reader/{OrientationModeSelectDialog.kt => OrientationSelectDialog.kt} (79%) rename app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/{OrientationType.kt => ReaderOrientation.kt} (91%) rename app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/{ReadingModeType.kt => ReadingMode.kt} (50%) diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/SetMangaViewerFlags.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/SetMangaViewerFlags.kt index 8ffc27bb9..083d26e98 100644 --- a/app/src/main/java/eu/kanade/domain/manga/interactor/SetMangaViewerFlags.kt +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/SetMangaViewerFlags.kt @@ -1,7 +1,7 @@ package eu.kanade.domain.manga.interactor -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType -import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType +import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation +import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import tachiyomi.domain.manga.model.MangaUpdate import tachiyomi.domain.manga.repository.MangaRepository @@ -14,7 +14,7 @@ class SetMangaViewerFlags( mangaRepository.update( MangaUpdate( id = id, - viewerFlags = manga.viewerFlags.setFlag(flag, ReadingModeType.MASK.toLong()), + viewerFlags = manga.viewerFlags.setFlag(flag, ReadingMode.MASK.toLong()), ), ) } @@ -24,7 +24,7 @@ class SetMangaViewerFlags( mangaRepository.update( MangaUpdate( id = id, - viewerFlags = manga.viewerFlags.setFlag(flag, OrientationType.MASK.toLong()), + viewerFlags = manga.viewerFlags.setFlag(flag, ReaderOrientation.MASK.toLong()), ), ) } diff --git a/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt b/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt index 6c2ee4a5e..686b29f43 100644 --- a/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt +++ b/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt @@ -3,8 +3,8 @@ package eu.kanade.domain.manga.model import eu.kanade.domain.base.BasePreferences import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.source.model.SManga -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType -import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType +import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation +import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import tachiyomi.core.metadata.comicinfo.ComicInfo import tachiyomi.core.metadata.comicinfo.ComicInfoPublishingStatus import tachiyomi.core.preference.TriState @@ -14,11 +14,11 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get // TODO: move these into the domain model -val Manga.readingModeType: Long - get() = viewerFlags and ReadingModeType.MASK.toLong() +val Manga.readingMode: Long + get() = viewerFlags and ReadingMode.MASK.toLong() -val Manga.orientationType: Long - get() = viewerFlags and OrientationType.MASK.toLong() +val Manga.readerOrientation: Long + get() = viewerFlags and ReaderOrientation.MASK.toLong() val Manga.downloadedFilter: TriState get() { 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 4d975200a..ab2759c39 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 @@ -10,9 +10,9 @@ import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource import eu.kanade.presentation.more.settings.Preference import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType +import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences -import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType +import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import tachiyomi.presentation.core.util.collectAsState import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -32,7 +32,7 @@ object SettingsReaderScreen : SearchableSettings { Preference.PreferenceItem.ListPreference( pref = readerPref.defaultReadingMode(), title = stringResource(R.string.pref_viewer_type), - entries = ReadingModeType.entries.drop(1) + entries = ReadingMode.entries.drop(1) .associate { it.flagValue to stringResource(it.stringRes) }, ), Preference.PreferenceItem.ListPreference( @@ -88,7 +88,7 @@ object SettingsReaderScreen : SearchableSettings { Preference.PreferenceItem.ListPreference( pref = readerPreferences.defaultOrientationType(), title = stringResource(R.string.pref_rotation_type), - entries = OrientationType.entries.drop(1) + entries = ReaderOrientation.entries.drop(1) .associate { it.flagValue to stringResource(it.stringRes) }, ), Preference.PreferenceItem.ListPreference( diff --git a/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/OrientationSelectDialog.kt similarity index 79% rename from app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt rename to app/src/main/java/eu/kanade/presentation/reader/OrientationSelectDialog.kt index a143634ab..08a08c08b 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/OrientationSelectDialog.kt @@ -13,28 +13,28 @@ 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.domain.manga.model.readerOrientation import eu.kanade.presentation.components.AdaptiveSheet import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType +import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import tachiyomi.presentation.core.components.SettingsIconGrid import tachiyomi.presentation.core.components.material.IconToggleButton import tachiyomi.presentation.core.util.ThemePreviews @Composable -fun OrientationModeSelectDialog( +fun OrientationSelectDialog( onDismissRequest: () -> Unit, screenModel: ReaderSettingsScreenModel, onChange: (Int) -> Unit, ) { val manga by screenModel.mangaFlow.collectAsState() - val orientationType = remember(manga) { OrientationType.fromPreference(manga?.orientationType?.toInt()) } + val orientation = remember(manga) { ReaderOrientation.fromPreference(manga?.readerOrientation?.toInt()) } AdaptiveSheet(onDismissRequest = onDismissRequest) { DialogContent( - orientationType = orientationType, + orientation = orientation, onChangeOrientation = { screenModel.onChangeOrientation(it) onChange(it.stringRes) @@ -46,14 +46,14 @@ fun OrientationModeSelectDialog( @Composable private fun DialogContent( - orientationType: OrientationType, - onChangeOrientation: (OrientationType) -> Unit, + orientation: ReaderOrientation, + onChangeOrientation: (ReaderOrientation) -> Unit, ) { Box(modifier = Modifier.padding(vertical = 16.dp)) { SettingsIconGrid(R.string.rotation_type) { - items(OrientationType.entries) { mode -> + items(ReaderOrientation.entries) { mode -> IconToggleButton( - checked = mode == orientationType, + checked = mode == orientation, onCheckedChange = { onChangeOrientation(mode) }, @@ -71,7 +71,7 @@ private fun DialogContent( private fun DialogContentPreview() { TachiyomiTheme { DialogContent( - orientationType = OrientationType.DEFAULT, + orientation = ReaderOrientation.DEFAULT, onChangeOrientation = {}, ) } 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 a2089c7f5..2d976f92a 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt @@ -13,12 +13,12 @@ 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 eu.kanade.domain.manga.model.readingModeType +import eu.kanade.domain.manga.model.readingMode import eu.kanade.presentation.components.AdaptiveSheet import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel -import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType +import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import tachiyomi.presentation.core.components.SettingsIconGrid import tachiyomi.presentation.core.components.material.IconToggleButton import tachiyomi.presentation.core.components.material.padding @@ -31,7 +31,7 @@ fun ReadingModeSelectDialog( onChange: (Int) -> Unit, ) { val manga by screenModel.mangaFlow.collectAsState() - val readingMode = remember(manga) { ReadingModeType.fromPreference(manga?.readingModeType?.toInt()) } + val readingMode = remember(manga) { ReadingMode.fromPreference(manga?.readingMode?.toInt()) } AdaptiveSheet(onDismissRequest = onDismissRequest) { DialogContent( @@ -47,12 +47,12 @@ fun ReadingModeSelectDialog( @Composable private fun DialogContent( - readingMode: ReadingModeType, - onChangeReadingMode: (ReadingModeType) -> Unit, + readingMode: ReadingMode, + onChangeReadingMode: (ReadingMode) -> Unit, ) { Box(modifier = Modifier.padding(vertical = MaterialTheme.padding.medium)) { SettingsIconGrid(R.string.pref_category_reading_mode) { - items(ReadingModeType.entries) { mode -> + items(ReadingMode.entries) { mode -> IconToggleButton( checked = mode == readingMode, onCheckedChange = { @@ -72,7 +72,7 @@ private fun DialogContent( private fun DialogContentPreview() { TachiyomiTheme { DialogContent( - readingMode = ReadingModeType.DEFAULT, + readingMode = ReadingMode.DEFAULT, onChangeReadingMode = {}, ) } diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt index e48867fcb..041f68c5e 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt @@ -17,16 +17,16 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType -import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType +import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation +import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode @Composable fun BottomReaderBar( backgroundColor: Color, - readingMode: ReadingModeType, + readingMode: ReadingMode, onClickReadingMode: () -> Unit, - orientationMode: OrientationType, - onClickOrientationMode: () -> Unit, + orientation: ReaderOrientation, + onClickOrientation: () -> Unit, cropEnabled: Boolean, onClickCropBorder: () -> Unit, onClickSettings: () -> Unit, @@ -53,9 +53,9 @@ fun BottomReaderBar( ) } - IconButton(onClick = onClickOrientationMode) { + IconButton(onClick = onClickOrientation) { Icon( - painter = painterResource(orientationMode.iconRes), + painter = painterResource(orientation.iconRes), contentDescription = stringResource(R.string.pref_rotation_type), ) } diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt index 7b360b04d..de3d0131f 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -24,8 +24,8 @@ import androidx.compose.ui.unit.dp import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBarActions import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType -import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType +import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation +import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import eu.kanade.tachiyomi.ui.reader.viewer.Viewer import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer @@ -54,10 +54,10 @@ fun ReaderAppBars( totalPages: Int, onSliderValueChange: (Int) -> Unit, - readingMode: ReadingModeType, + readingMode: ReadingMode, onClickReadingMode: () -> Unit, - orientationMode: OrientationType, - onClickOrientationMode: () -> Unit, + orientation: ReaderOrientation, + onClickOrientation: () -> Unit, cropEnabled: Boolean, onClickCropBorder: () -> Unit, onClickSettings: () -> Unit, @@ -155,8 +155,8 @@ fun ReaderAppBars( backgroundColor = backgroundColor, readingMode = readingMode, onClickReadingMode = onClickReadingMode, - orientationMode = orientationMode, - onClickOrientationMode = onClickOrientationMode, + orientation = orientation, + onClickOrientation = onClickOrientation, cropEnabled = cropEnabled, onClickCropBorder = onClickCropBorder, onClickSettings = onClickSettings, 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 07d6cb49a..8bf1d0079 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 @@ -8,13 +8,13 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.res.stringResource -import eu.kanade.domain.manga.model.orientationType -import eu.kanade.domain.manga.model.readingModeType +import eu.kanade.domain.manga.model.readerOrientation +import eu.kanade.domain.manga.model.readingMode import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType +import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation 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.setting.ReadingMode import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.HeadingItem @@ -23,33 +23,29 @@ import tachiyomi.presentation.core.components.SliderItem import tachiyomi.presentation.core.util.collectAsState import java.text.NumberFormat -private val readingModeOptions = ReadingModeType.entries.map { it.stringRes to it } -private val orientationTypeOptions = OrientationType.entries.map { it.stringRes to it } -private val tappingInvertModeOptions = ReaderPreferences.TappingInvertMode.entries.map { it.titleResId to it } - @Composable internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel) { HeadingItem(R.string.pref_category_for_this_series) val manga by screenModel.mangaFlow.collectAsState() - val readingMode = remember(manga) { ReadingModeType.fromPreference(manga?.readingModeType?.toInt()) } + val readingMode = remember(manga) { ReadingMode.fromPreference(manga?.readingMode?.toInt()) } SettingsChipRow(R.string.pref_category_reading_mode) { - readingModeOptions.map { (stringRes, it) -> + ReadingMode.entries.map { FilterChip( selected = it == readingMode, onClick = { screenModel.onChangeReadingMode(it) }, - label = { Text(stringResource(stringRes)) }, + label = { Text(stringResource(it.stringRes)) }, ) } } - val orientationType = remember(manga) { OrientationType.fromPreference(manga?.orientationType?.toInt()) } + val orientation = remember(manga) { ReaderOrientation.fromPreference(manga?.readerOrientation?.toInt()) } SettingsChipRow(R.string.rotation_type) { - orientationTypeOptions.map { (stringRes, it) -> + ReaderOrientation.entries.map { FilterChip( - selected = it == orientationType, + selected = it == orientation, onClick = { screenModel.onChangeOrientation(it) }, - label = { Text(stringResource(stringRes)) }, + label = { Text(stringResource(it.stringRes)) }, ) } } @@ -209,11 +205,11 @@ private fun ColumnScope.TapZonesItems( if (selected != 5) { SettingsChipRow(R.string.pref_read_with_tapping_inverted) { - tappingInvertModeOptions.map { (stringRes, mode) -> + ReaderPreferences.TappingInvertMode.entries.map { FilterChip( - selected = mode == invertMode, - onClick = { onSelectInvertMode(mode) }, - label = { Text(stringResource(stringRes)) }, + selected = it == invertMode, + onClick = { onSelectInvertMode(it) }, + label = { Text(stringResource(it.titleResId)) }, ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index bd672e316..b3889f2e7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -12,7 +12,7 @@ import eu.kanade.tachiyomi.data.library.LibraryUpdateJob 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 +import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.toast @@ -170,12 +170,12 @@ object Migrations { if (oldVersion < 60) { // Migrate Rotation and Viewer values to default values for viewer_flags val newOrientation = when (prefs.getInt("pref_rotation_type_key", 1)) { - 1 -> OrientationType.FREE.flagValue - 2 -> OrientationType.PORTRAIT.flagValue - 3 -> OrientationType.LANDSCAPE.flagValue - 4 -> OrientationType.LOCKED_PORTRAIT.flagValue - 5 -> OrientationType.LOCKED_LANDSCAPE.flagValue - else -> OrientationType.FREE.flagValue + 1 -> ReaderOrientation.FREE.flagValue + 2 -> ReaderOrientation.PORTRAIT.flagValue + 3 -> ReaderOrientation.LANDSCAPE.flagValue + 4 -> ReaderOrientation.LOCKED_PORTRAIT.flagValue + 5 -> ReaderOrientation.LOCKED_LANDSCAPE.flagValue + else -> ReaderOrientation.FREE.flagValue } // Reading mode flag and prefValue is the same value diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt index a3d0f4493..8dd429c15 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt @@ -1,7 +1,7 @@ package eu.kanade.tachiyomi.data.backup.models import eu.kanade.tachiyomi.source.model.UpdateStrategy -import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType +import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber import tachiyomi.domain.chapter.model.Chapter @@ -89,7 +89,7 @@ data class BackupManga( favorite = manga.favorite, source = manga.source, dateAdded = manga.dateAdded, - viewer = (manga.viewerFlags.toInt() and ReadingModeType.MASK), + viewer = (manga.viewerFlags.toInt() and ReadingMode.MASK), viewer_flags = manga.viewerFlags.toInt(), chapterFlags = manga.chapterFlags.toInt(), updateStrategy = manga.updateStrategy, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index a9428213f..108b9dcef 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -44,7 +44,7 @@ import dev.chrisbanes.insetter.applyInsetter import eu.kanade.domain.base.BasePreferences import eu.kanade.presentation.reader.BrightnessOverlay import eu.kanade.presentation.reader.DisplayRefreshHost -import eu.kanade.presentation.reader.OrientationModeSelectDialog +import eu.kanade.presentation.reader.OrientationSelectDialog import eu.kanade.presentation.reader.PageIndicatorText import eu.kanade.presentation.reader.ReaderPageActionsDialog import eu.kanade.presentation.reader.ReadingModeSelectDialog @@ -63,10 +63,10 @@ import eu.kanade.tachiyomi.ui.reader.ReaderViewModel.SetAsCoverResult.Success import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType +import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation 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.setting.ReadingMode import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator import eu.kanade.tachiyomi.ui.webview.WebViewActivity import eu.kanade.tachiyomi.util.system.hasDisplayCutout @@ -332,7 +332,7 @@ class ReaderActivity : BaseActivity() { val cropBorderPaged by readerPreferences.cropBorders().collectAsState() val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() - val isPagerType = ReadingModeType.isPagerType(viewModel.getMangaReadingMode()) + val isPagerType = ReadingMode.isPagerType(viewModel.getMangaReadingMode()) val cropEnabled = if (isPagerType) cropBorderPaged else cropBorderWebtoon ReaderAppBars( @@ -360,14 +360,14 @@ class ReaderActivity : BaseActivity() { moveToPageIndex(it) }, - readingMode = ReadingModeType.fromPreference( + readingMode = ReadingMode.fromPreference( viewModel.getMangaReadingMode(resolveDefault = false), ), onClickReadingMode = viewModel::openReadingModeSelectDialog, - orientationMode = OrientationType.fromPreference( - viewModel.getMangaOrientationType(resolveDefault = false), + orientation = ReaderOrientation.fromPreference( + viewModel.getMangaOrientation(resolveDefault = false), ), - onClickOrientationMode = viewModel::openOrientationModeSelectDialog, + onClickOrientation = viewModel::openOrientationModeSelectDialog, cropEnabled = cropEnabled, onClickCropBorder = { val enabled = viewModel.toggleCropBorders() @@ -425,7 +425,7 @@ class ReaderActivity : BaseActivity() { ) } is ReaderViewModel.Dialog.OrientationModeSelect -> { - OrientationModeSelectDialog( + OrientationSelectDialog( onDismissRequest = onDismissRequest, screenModel = settingsScreenModel, onChange = { stringRes -> @@ -482,15 +482,15 @@ class ReaderActivity : BaseActivity() { */ private fun setManga(manga: Manga) { val prevViewer = viewModel.state.value.viewer - val newViewer = ReadingModeType.toViewer(viewModel.getMangaReadingMode(), this) + val newViewer = ReadingMode.toViewer(viewModel.getMangaReadingMode(), this) if (window.sharedElementEnterTransition is MaterialContainerTransform) { // Wait until transition is complete to avoid crash on API 26 window.sharedElementEnterTransition.doOnEnd { - setOrientation(viewModel.getMangaOrientationType()) + setOrientation(viewModel.getMangaOrientation()) } } else { - setOrientation(viewModel.getMangaOrientationType()) + setOrientation(viewModel.getMangaOrientation()) } // Destroy previous viewer if there was one @@ -543,7 +543,7 @@ class ReaderActivity : BaseActivity() { private fun showReadingModeToast(mode: Int) { try { readingModeToast?.cancel() - readingModeToast = toast(ReadingModeType.fromPreference(mode).stringRes) + readingModeToast = toast(ReadingMode.fromPreference(mode).stringRes) } catch (e: ArrayIndexOutOfBoundsException) { logcat(LogPriority.ERROR) { "Unknown reading mode: $mode" } } @@ -721,7 +721,7 @@ class ReaderActivity : BaseActivity() { * Forces the user preferred [orientation] on the activity. */ private fun setOrientation(orientation: Int) { - val newOrientation = OrientationType.fromPreference(orientation) + val newOrientation = ReaderOrientation.fromPreference(orientation) if (newOrientation.flag != requestedOrientation) { requestedOrientation = newOrientation.flag } 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 0fae11b49..6718f6935 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 @@ -10,8 +10,8 @@ import androidx.lifecycle.viewModelScope import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.chapter.model.toDbChapter import eu.kanade.domain.manga.interactor.SetMangaViewerFlags -import eu.kanade.domain.manga.model.orientationType -import eu.kanade.domain.manga.model.readingModeType +import eu.kanade.domain.manga.model.readerOrientation +import eu.kanade.domain.manga.model.readingMode import eu.kanade.domain.track.interactor.TrackChapter import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.tachiyomi.data.database.models.toDomainChapter @@ -29,9 +29,9 @@ 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.ViewerChapters -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType +import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences -import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType +import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import eu.kanade.tachiyomi.ui.reader.viewer.Viewer import eu.kanade.tachiyomi.util.chapter.filterDownloaded import eu.kanade.tachiyomi.util.chapter.removeDuplicates @@ -630,20 +630,20 @@ class ReaderViewModel @JvmOverloads constructor( */ fun getMangaReadingMode(resolveDefault: Boolean = true): Int { val default = readerPreferences.defaultReadingMode().get() - val readingMode = ReadingModeType.fromPreference(manga?.readingModeType?.toInt()) + val readingMode = ReadingMode.fromPreference(manga?.readingMode?.toInt()) return when { - resolveDefault && readingMode == ReadingModeType.DEFAULT -> default - else -> manga?.readingModeType?.toInt() ?: default + resolveDefault && readingMode == ReadingMode.DEFAULT -> default + else -> manga?.readingMode?.toInt() ?: default } } /** * Updates the viewer position for the open manga. */ - fun setMangaReadingMode(readingModeType: ReadingModeType) { + fun setMangaReadingMode(readingMode: ReadingMode) { val manga = manga ?: return runBlocking(Dispatchers.IO) { - setMangaViewerFlags.awaitSetReadingMode(manga.id, readingModeType.flagValue.toLong()) + setMangaViewerFlags.awaitSetReadingMode(manga.id, readingMode.flagValue.toLong()) val currChapters = state.value.viewerChapters if (currChapters != null) { // Save current page @@ -664,22 +664,22 @@ class ReaderViewModel @JvmOverloads constructor( /** * Returns the orientation type used by this manga or the default one. */ - fun getMangaOrientationType(resolveDefault: Boolean = true): Int { + fun getMangaOrientation(resolveDefault: Boolean = true): Int { val default = readerPreferences.defaultOrientationType().get() - val orientation = OrientationType.fromPreference(manga?.orientationType?.toInt()) + val orientation = ReaderOrientation.fromPreference(manga?.readerOrientation?.toInt()) return when { - resolveDefault && orientation == OrientationType.DEFAULT -> default - else -> manga?.orientationType?.toInt() ?: default + resolveDefault && orientation == ReaderOrientation.DEFAULT -> default + else -> manga?.readerOrientation?.toInt() ?: default } } /** * Updates the orientation type for the open manga. */ - fun setMangaOrientationType(rotationType: OrientationType) { + fun setMangaOrientationType(orientation: ReaderOrientation) { val manga = manga ?: return viewModelScope.launchIO { - setMangaViewerFlags.awaitSetOrientation(manga.id, rotationType.flagValue.toLong()) + setMangaViewerFlags.awaitSetOrientation(manga.id, orientation.flagValue.toLong()) val currChapters = state.value.viewerChapters if (currChapters != null) { // Save current page @@ -692,14 +692,14 @@ class ReaderViewModel @JvmOverloads constructor( viewerChapters = currChapters, ) } - eventChannel.send(Event.SetOrientation(getMangaOrientationType())) + eventChannel.send(Event.SetOrientation(getMangaOrientation())) eventChannel.send(Event.ReloadViewerChapters) } } } fun toggleCropBorders(): Boolean { - val isPagerType = ReadingModeType.isPagerType(getMangaReadingMode()) + val isPagerType = ReadingMode.isPagerType(getMangaReadingMode()) return if (isPagerType) { readerPreferences.cropBorders().toggle() } else { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderOrientation.kt similarity index 91% rename from app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderOrientation.kt index c2edb39e9..c1d2e9b2d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderOrientation.kt @@ -5,7 +5,7 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import eu.kanade.tachiyomi.R -enum class OrientationType( +enum class ReaderOrientation( val flag: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int, @@ -58,6 +58,6 @@ enum class OrientationType( companion object { const val MASK = 0x00000038 - fun fromPreference(preference: Int?): OrientationType = entries.find { it.flagValue == preference } ?: DEFAULT + fun fromPreference(preference: Int?): ReaderOrientation = entries.find { it.flagValue == preference } ?: DEFAULT } } 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 5b2314916..9389a89e9 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 @@ -32,12 +32,12 @@ class ReaderPreferences( fun defaultReadingMode() = preferenceStore.getInt( "pref_default_reading_mode_key", - ReadingModeType.RIGHT_TO_LEFT.flagValue, + ReadingMode.RIGHT_TO_LEFT.flagValue, ) fun defaultOrientationType() = preferenceStore.getInt( "pref_default_orientation_type_key", - OrientationType.FREE.flagValue, + ReaderOrientation.FREE.flagValue, ) fun webtoonDoubleTapZoomEnabled() = preferenceStore.getBoolean("pref_enable_double_tap_zoom_webtoon", true) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt index 5014ba204..5f107c388 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsScreenModel.kt @@ -14,8 +14,8 @@ import uy.kohesive.injekt.api.get class ReaderSettingsScreenModel( readerState: StateFlow, val hasDisplayCutout: Boolean, - val onChangeReadingMode: (ReadingModeType) -> Unit, - val onChangeOrientation: (OrientationType) -> Unit, + val onChangeReadingMode: (ReadingMode) -> Unit, + val onChangeOrientation: (ReaderOrientation) -> Unit, val preferences: ReaderPreferences = Injekt.get(), ) : ScreenModel { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingMode.kt similarity index 50% rename from app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingMode.kt index 4d5974ee5..d042795eb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingMode.kt @@ -10,27 +10,59 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer -enum class ReadingModeType( +enum class ReadingMode( @StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int, + val direction: Direction? = null, + val type: ViewerType? = null, ) { DEFAULT(R.string.label_default, R.drawable.ic_reader_default_24dp, 0x00000000), - LEFT_TO_RIGHT(R.string.left_to_right_viewer, R.drawable.ic_reader_ltr_24dp, 0x00000001), - RIGHT_TO_LEFT(R.string.right_to_left_viewer, R.drawable.ic_reader_rtl_24dp, 0x00000002), - VERTICAL(R.string.vertical_viewer, R.drawable.ic_reader_vertical_24dp, 0x00000003), - WEBTOON(R.string.webtoon_viewer, R.drawable.ic_reader_webtoon_24dp, 0x00000004), - CONTINUOUS_VERTICAL(R.string.vertical_plus_viewer, R.drawable.ic_reader_continuous_vertical_24dp, 0x00000005), + LEFT_TO_RIGHT( + R.string.left_to_right_viewer, + R.drawable.ic_reader_ltr_24dp, + 0x00000001, + Direction.Horizontal, + ViewerType.Pager, + ), + RIGHT_TO_LEFT( + R.string.right_to_left_viewer, + R.drawable.ic_reader_rtl_24dp, + 0x00000002, + Direction.Horizontal, + ViewerType.Pager, + ), + VERTICAL( + R.string.vertical_viewer, + R.drawable.ic_reader_vertical_24dp, + 0x00000003, + Direction.Vertical, + ViewerType.Pager, + ), + WEBTOON( + R.string.webtoon_viewer, + R.drawable.ic_reader_webtoon_24dp, + 0x00000004, + Direction.Vertical, + ViewerType.Webtoon, + ), + CONTINUOUS_VERTICAL( + R.string.vertical_plus_viewer, + R.drawable.ic_reader_continuous_vertical_24dp, + 0x00000005, + Direction.Vertical, + ViewerType.Webtoon, + ), ; companion object { const val MASK = 0x00000007 - fun fromPreference(preference: Int?): ReadingModeType = entries.find { it.flagValue == preference } ?: DEFAULT + fun fromPreference(preference: Int?): ReadingMode = entries.find { it.flagValue == preference } ?: DEFAULT fun isPagerType(preference: Int): Boolean { val mode = fromPreference(preference) - return mode == LEFT_TO_RIGHT || mode == RIGHT_TO_LEFT || mode == VERTICAL + return mode.type is ViewerType.Pager } fun toViewer(preference: Int?, activity: ReaderActivity): Viewer { @@ -44,4 +76,14 @@ enum class ReadingModeType( } } } + + sealed interface Direction { + data object Horizontal : Direction + data object Vertical : Direction + } + + sealed interface ViewerType { + data object Pager : ViewerType + data object Webtoon : ViewerType + } } From e6ca54fd04668fde5ae12429101a13dc1f03b99e Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 5 Nov 2023 10:34:19 -0500 Subject: [PATCH 55/66] Replace custom preview annotation --- .../presentation/components/EmptyScreen.kt | 6 +-- .../kanade/presentation/crash/CrashScreen.kt | 4 +- .../presentation/history/HistoryScreen.kt | 4 +- .../history/components/HistoryDialogs.kt | 4 +- .../history/components/HistoryItem.kt | 19 ++++++---- .../library/components/LibraryBadges.kt | 4 +- .../presentation/more/NewUpdateScreen.kt | 4 +- .../widget/AppThemePreferenceWidget.kt | 16 ++++---- .../more/settings/widget/InfoWidget.kt | 4 +- .../settings/widget/SwitchPreferenceWidget.kt | 4 +- .../settings/widget/TextPreferenceWidget.kt | 4 +- .../presentation/reader/ChapterTransition.kt | 12 +++--- .../reader/OrientationSelectDialog.kt | 15 +++++--- .../presentation/reader/PageIndicatorText.kt | 9 +++-- .../reader/ReadingModeSelectDialog.kt | 15 +++++--- .../presentation/track/TrackInfoDialogHome.kt | 11 ++++-- .../track/TrackInfoDialogSelector.kt | 37 ++++++++++--------- .../presentation/track/TrackerSearch.kt | 4 +- .../track/components/TrackLogoIcon.kt | 4 +- .../presentation/core/screens/InfoScreen.kt | 4 +- .../presentation/core/util/ThemePreviews.kt | 15 -------- 21 files changed, 103 insertions(+), 96 deletions(-) delete mode 100644 presentation-core/src/main/java/tachiyomi/presentation/core/util/ThemePreviews.kt diff --git a/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt b/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt index fad8fd650..def969a39 100644 --- a/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt @@ -5,13 +5,13 @@ import androidx.compose.material.icons.outlined.HelpOutline import androidx.compose.material.icons.outlined.Refresh import androidx.compose.material3.Surface import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewLightDark import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import tachiyomi.presentation.core.screens.EmptyScreen import tachiyomi.presentation.core.screens.EmptyScreenAction -import tachiyomi.presentation.core.util.ThemePreviews -@ThemePreviews +@PreviewLightDark @Composable private fun NoActionPreview() { TachiyomiTheme { @@ -23,7 +23,7 @@ private fun NoActionPreview() { } } -@ThemePreviews +@PreviewLightDark @Composable private fun WithActionPreview() { TachiyomiTheme { diff --git a/app/src/main/java/eu/kanade/presentation/crash/CrashScreen.kt b/app/src/main/java/eu/kanade/presentation/crash/CrashScreen.kt index 3ed6d15fc..932f02e16 100644 --- a/app/src/main/java/eu/kanade/presentation/crash/CrashScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/crash/CrashScreen.kt @@ -14,13 +14,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewLightDark import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.CrashLogUtil import kotlinx.coroutines.launch import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.screens.InfoScreen -import tachiyomi.presentation.core.util.ThemePreviews @Composable fun CrashScreen( @@ -60,7 +60,7 @@ fun CrashScreen( } } -@ThemePreviews +@PreviewLightDark @Composable private fun CrashScreenPreview() { TachiyomiTheme { 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 b2ffb6e5e..08db8aa24 100644 --- a/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewParameter import eu.kanade.domain.ui.UiPreferences import eu.kanade.presentation.components.AppBar @@ -28,7 +29,6 @@ import tachiyomi.presentation.core.components.FastScrollLazyColumn import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.screens.EmptyScreen import tachiyomi.presentation.core.screens.LoadingScreen -import tachiyomi.presentation.core.util.ThemePreviews import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.util.Date @@ -148,7 +148,7 @@ sealed interface HistoryUiModel { data class Item(val item: HistoryWithRelations) : HistoryUiModel } -@ThemePreviews +@PreviewLightDark @Composable internal fun HistoryScreenPreviews( @PreviewParameter(HistoryScreenModelStateProvider::class) 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 0ceab8f61..5e9027ba0 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 @@ -11,11 +11,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import tachiyomi.presentation.core.components.LabeledCheckbox -import tachiyomi.presentation.core.util.ThemePreviews @Composable fun HistoryDeleteDialog( @@ -87,7 +87,7 @@ fun HistoryDeleteAllDialog( ) } -@ThemePreviews +@PreviewLightDark @Composable private fun HistoryDeleteDialogPreview() { TachiyomiTheme { diff --git a/app/src/main/java/eu/kanade/presentation/history/components/HistoryItem.kt b/app/src/main/java/eu/kanade/presentation/history/components/HistoryItem.kt index cd37192f6..148a8e693 100644 --- a/app/src/main/java/eu/kanade/presentation/history/components/HistoryItem.kt +++ b/app/src/main/java/eu/kanade/presentation/history/components/HistoryItem.kt @@ -11,6 +11,7 @@ import androidx.compose.material.icons.outlined.Delete import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -19,6 +20,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import eu.kanade.presentation.manga.components.MangaCover @@ -28,7 +30,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.lang.toTimestampString import tachiyomi.domain.history.model.HistoryWithRelations import tachiyomi.presentation.core.components.material.padding -import tachiyomi.presentation.core.util.ThemePreviews private val HistoryItemHeight = 96.dp @@ -91,18 +92,20 @@ fun HistoryItem( } } -@ThemePreviews +@PreviewLightDark @Composable private fun HistoryItemPreviews( @PreviewParameter(HistoryWithRelationsProvider::class) historyWithRelations: HistoryWithRelations, ) { TachiyomiTheme { - HistoryItem( - history = historyWithRelations, - onClickCover = {}, - onClickResume = {}, - onClickDelete = {}, - ) + Surface { + HistoryItem( + history = historyWithRelations, + onClickCover = {}, + onClickResume = {}, + onClickDelete = {}, + ) + } } } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryBadges.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryBadges.kt index 0ab1a3c28..608edb8f4 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryBadges.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryBadges.kt @@ -5,9 +5,9 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Folder import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewLightDark import eu.kanade.presentation.theme.TachiyomiTheme import tachiyomi.presentation.core.components.Badge -import tachiyomi.presentation.core.util.ThemePreviews @Composable internal fun DownloadsBadge(count: Long) { @@ -47,7 +47,7 @@ internal fun LanguageBadge( } } -@ThemePreviews +@PreviewLightDark @Composable private fun BadgePreview() { TachiyomiTheme { diff --git a/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt b/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt index 5e1c4d7ce..0cd661e85 100644 --- a/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.tooling.preview.PreviewLightDark import com.halilibo.richtext.markdown.Markdown import com.halilibo.richtext.ui.RichTextStyle import com.halilibo.richtext.ui.material3.Material3RichText @@ -23,7 +24,6 @@ import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.screens.InfoScreen -import tachiyomi.presentation.core.util.ThemePreviews @Composable fun NewUpdateScreen( @@ -66,7 +66,7 @@ fun NewUpdateScreen( } } -@ThemePreviews +@PreviewLightDark @Composable private fun NewUpdateScreenPreview() { TachiyomiTheme { diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt index fef522408..484bb52eb 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt @@ -38,6 +38,7 @@ import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp import eu.kanade.domain.ui.model.AppTheme import eu.kanade.presentation.manga.components.MangaCover @@ -46,7 +47,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable import tachiyomi.presentation.core.components.material.padding -import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.secondaryItemAlpha @Composable @@ -249,15 +249,17 @@ fun AppThemePreviewItem( } } -@ThemePreviews +@PreviewLightDark @Composable private fun AppThemesListPreview() { var appTheme by remember { mutableStateOf(AppTheme.DEFAULT) } TachiyomiTheme { - AppThemesList( - currentTheme = appTheme, - amoled = false, - onItemClick = { appTheme = it }, - ) + Surface { + AppThemesList( + currentTheme = appTheme, + amoled = false, + onItemClick = { appTheme = it }, + ) + } } } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/InfoWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/InfoWidget.kt index 1183414e2..2dbb54be0 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/InfoWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/InfoWidget.kt @@ -12,10 +12,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewLightDark import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import tachiyomi.presentation.core.components.material.padding -import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.secondaryItemAlpha @Composable @@ -40,7 +40,7 @@ internal fun InfoWidget(text: String) { } } -@ThemePreviews +@PreviewLightDark @Composable private fun InfoWidgetPreview() { TachiyomiTheme { diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/SwitchPreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/SwitchPreferenceWidget.kt index 7de5c68d3..bc026d3ba 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/SwitchPreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/SwitchPreferenceWidget.kt @@ -9,8 +9,8 @@ import androidx.compose.material3.Switch import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.tooling.preview.PreviewLightDark import eu.kanade.presentation.theme.TachiyomiTheme -import tachiyomi.presentation.core.util.ThemePreviews @Composable fun SwitchPreferenceWidget( @@ -37,7 +37,7 @@ fun SwitchPreferenceWidget( ) } -@ThemePreviews +@PreviewLightDark @Composable private fun SwitchPreferenceWidgetPreview() { TachiyomiTheme { diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TextPreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TextPreferenceWidget.kt index bd8ac4593..05bd7f85d 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TextPreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TextPreferenceWidget.kt @@ -12,8 +12,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.tooling.preview.PreviewLightDark import eu.kanade.presentation.theme.TachiyomiTheme -import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.secondaryItemAlpha @Composable @@ -59,7 +59,7 @@ fun TextPreferenceWidget( ) } -@ThemePreviews +@PreviewLightDark @Composable private fun TextPreferenceWidgetPreview() { TachiyomiTheme { diff --git a/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt b/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt index a153b37b1..cb6ca9a8b 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ChapterTransition.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.text.Placeholder import androidx.compose.ui.text.PlaceholderVerticalAlign import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import eu.kanade.presentation.theme.TachiyomiTheme @@ -42,7 +43,6 @@ import eu.kanade.tachiyomi.data.database.models.toDomainChapter import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import tachiyomi.domain.chapter.service.calculateChapterGap -import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.secondaryItemAlpha @Composable @@ -304,7 +304,7 @@ private val FakeChapterLongTitle = previewChapter( chapterNumber = 1f, ) -@ThemePreviews +@PreviewLightDark @Composable private fun TransitionTextPreview() { TachiyomiTheme { @@ -318,7 +318,7 @@ private fun TransitionTextPreview() { } } -@ThemePreviews +@PreviewLightDark @Composable private fun TransitionTextLongTitlePreview() { TachiyomiTheme { @@ -332,7 +332,7 @@ private fun TransitionTextLongTitlePreview() { } } -@ThemePreviews +@PreviewLightDark @Composable private fun TransitionTextWithGapPreview() { TachiyomiTheme { @@ -346,7 +346,7 @@ private fun TransitionTextWithGapPreview() { } } -@ThemePreviews +@PreviewLightDark @Composable private fun TransitionTextNoNextPreview() { TachiyomiTheme { @@ -360,7 +360,7 @@ private fun TransitionTextNoNextPreview() { } } -@ThemePreviews +@PreviewLightDark @Composable private fun TransitionTextNoPreviousPreview() { TachiyomiTheme { diff --git a/app/src/main/java/eu/kanade/presentation/reader/OrientationSelectDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/OrientationSelectDialog.kt index 08a08c08b..3d0e1143e 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/OrientationSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/OrientationSelectDialog.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.items +import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -12,6 +13,7 @@ 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.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp import eu.kanade.domain.manga.model.readerOrientation import eu.kanade.presentation.components.AdaptiveSheet @@ -21,7 +23,6 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import tachiyomi.presentation.core.components.SettingsIconGrid import tachiyomi.presentation.core.components.material.IconToggleButton -import tachiyomi.presentation.core.util.ThemePreviews @Composable fun OrientationSelectDialog( @@ -66,13 +67,15 @@ private fun DialogContent( } } -@ThemePreviews +@PreviewLightDark @Composable private fun DialogContentPreview() { TachiyomiTheme { - DialogContent( - orientation = ReaderOrientation.DEFAULT, - onChangeOrientation = {}, - ) + Surface { + DialogContent( + orientation = ReaderOrientation.DEFAULT, + onChangeOrientation = {}, + ) + } } } 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 470a731c8..ab2b05095 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/PageIndicatorText.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/PageIndicatorText.kt @@ -2,6 +2,7 @@ package eu.kanade.presentation.reader import androidx.compose.foundation.layout.Box import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -9,9 +10,9 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.sp import eu.kanade.presentation.theme.TachiyomiTheme -import tachiyomi.presentation.core.util.ThemePreviews @Composable fun PageIndicatorText( @@ -47,10 +48,12 @@ fun PageIndicatorText( } } -@ThemePreviews +@PreviewLightDark @Composable private fun PageIndicatorTextPreview() { TachiyomiTheme { - PageIndicatorText(currentPage = 10, totalPages = 69) + Surface { + PageIndicatorText(currentPage = 10, totalPages = 69) + } } } 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 2d976f92a..e9a669e17 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.items import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -13,6 +14,7 @@ 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.tooling.preview.PreviewLightDark import eu.kanade.domain.manga.model.readingMode import eu.kanade.presentation.components.AdaptiveSheet import eu.kanade.presentation.theme.TachiyomiTheme @@ -22,7 +24,6 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import tachiyomi.presentation.core.components.SettingsIconGrid import tachiyomi.presentation.core.components.material.IconToggleButton import tachiyomi.presentation.core.components.material.padding -import tachiyomi.presentation.core.util.ThemePreviews @Composable fun ReadingModeSelectDialog( @@ -67,13 +68,15 @@ private fun DialogContent( } } -@ThemePreviews +@PreviewLightDark @Composable private fun DialogContentPreview() { TachiyomiTheme { - DialogContent( - readingMode = ReadingMode.DEFAULT, - onChangeReadingMode = {}, - ) + Surface { + DialogContent( + readingMode = ReadingMode.DEFAULT, + onChangeReadingMode = {}, + ) + } } } 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 d0b31ca06..7125adbc0 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt @@ -28,6 +28,7 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.VerticalDivider @@ -44,6 +45,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import eu.kanade.domain.track.model.toDbTrack @@ -54,7 +56,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.ui.manga.track.TrackItem import eu.kanade.tachiyomi.util.system.copyToClipboard -import tachiyomi.presentation.core.util.ThemePreviews import java.text.DateFormat private const val UnsetStatusTextAlpha = 0.5F @@ -318,11 +319,15 @@ private fun TrackInfoItemMenu( } } -@ThemePreviews +@PreviewLightDark @Composable private fun TrackInfoDialogHomePreviews( @PreviewParameter(TrackInfoDialogHomePreviewProvider::class) content: @Composable () -> Unit, ) { - TachiyomiTheme { content() } + TachiyomiTheme { + Surface { + content() + } + } } diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt index b3afd2b28..012fc0466 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt @@ -20,6 +20,7 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.SelectableDates +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.minimumInteractiveComponentSize @@ -29,6 +30,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R @@ -37,7 +39,6 @@ import tachiyomi.presentation.core.components.WheelNumberPicker import tachiyomi.presentation.core.components.WheelTextPicker import tachiyomi.presentation.core.components.material.AlertDialogContent import tachiyomi.presentation.core.components.material.padding -import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.isScrolledToEnd import tachiyomi.presentation.core.util.isScrolledToStart @@ -221,24 +222,26 @@ private fun BaseSelector( ) } -@ThemePreviews +@PreviewLightDark @Composable private fun TrackStatusSelectorPreviews() { TachiyomiTheme { - TrackStatusSelector( - selection = 1, - onSelectionChange = {}, - selections = mapOf( - // Anilist values - 1 to R.string.reading, - 2 to R.string.plan_to_read, - 3 to R.string.completed, - 4 to R.string.on_hold, - 5 to R.string.dropped, - 6 to R.string.repeating, - ), - onConfirm = {}, - onDismissRequest = {}, - ) + Surface { + TrackStatusSelector( + selection = 1, + onSelectionChange = {}, + selections = mapOf( + // Anilist values + 1 to R.string.reading, + 2 to R.string.plan_to_read, + 3 to R.string.completed, + 4 to R.string.on_hold, + 5 to R.string.dropped, + 6 to R.string.repeating, + ), + onConfirm = {}, + onDismissRequest = {}, + ) + } } } diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt index df11b1ce1..63f2f3917 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt @@ -56,6 +56,7 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.toLowerCase +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import eu.kanade.presentation.manga.components.MangaCover @@ -67,7 +68,6 @@ import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.screens.EmptyScreen import tachiyomi.presentation.core.screens.LoadingScreen -import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.plus import tachiyomi.presentation.core.util.runOnEnterKeyPressed import tachiyomi.presentation.core.util.secondaryItemAlpha @@ -319,7 +319,7 @@ private fun SearchResultItemDetails( } } -@ThemePreviews +@PreviewLightDark @Composable private fun TrackerSearchPreviews( @PreviewParameter(TrackerSearchPreviewProvider::class) 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 63b7c6d02..835cce95c 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 @@ -11,11 +11,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.data.track.Tracker -import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.clickableNoIndication @Composable @@ -43,7 +43,7 @@ fun TrackLogoIcon( } } -@ThemePreviews +@PreviewLightDark @Composable private fun TrackLogoIconPreviews( @PreviewParameter(TrackLogoIconPreviewProvider::class) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/screens/InfoScreen.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/screens/InfoScreen.kt index 74f8211d9..b1a57a50e 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/screens/InfoScreen.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/screens/InfoScreen.kt @@ -23,12 +23,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.padding -import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.secondaryItemAlpha @Composable @@ -121,7 +121,7 @@ fun InfoScreen( } } -@ThemePreviews +@PreviewLightDark @Composable private fun InfoScaffoldPreview() { InfoScreen( diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/util/ThemePreviews.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/util/ThemePreviews.kt deleted file mode 100644 index 21dc9cabc..000000000 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/util/ThemePreviews.kt +++ /dev/null @@ -1,15 +0,0 @@ -package tachiyomi.presentation.core.util - -import android.content.res.Configuration -import androidx.compose.ui.tooling.preview.Preview - -@Preview( - name = "Light", - showBackground = true, -) -@Preview( - name = "Dark", - showBackground = true, - uiMode = Configuration.UI_MODE_NIGHT_YES, -) -annotation class ThemePreviews From b97aa235480e35b5514b7b1489b9d4413cea66d9 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sun, 5 Nov 2023 21:34:35 +0600 Subject: [PATCH 56/66] Implement scanlator filter (#8803) * Implement scanlator filter * Visual improvement to scanlator filter dialog * Review changes + Bug fixes Backup not containing filtered chapters and similar issue fix * Review Changes + Fix SQL query * Lint mamma mia --- app/build.gradle.kts | 2 +- .../java/eu/kanade/domain/DomainModule.kt | 8 +- .../interactor/GetAvailableScanlators.kt | 24 ++++ .../interactor/SyncChaptersWithSource.kt | 8 +- .../manga/interactor/GetExcludedScanlators.kt | 24 ++++ .../manga/interactor/SetExcludedScanlators.kt | 22 +++ .../manga/ChapterSettingsDialog.kt | 49 +++++++ .../kanade/presentation/manga/MangaScreen.kt | 5 +- .../manga/components/ScanlatorFilterDialog.kt | 134 ++++++++++++++++++ .../tachiyomi/data/backup/BackupCreator.kt | 12 +- .../ui/library/LibraryScreenModel.kt | 2 +- .../kanade/tachiyomi/ui/manga/MangaScreen.kt | 16 +++ .../tachiyomi/ui/manga/MangaScreenModel.kt | 48 ++++++- .../tachiyomi/ui/reader/ReaderViewModel.kt | 2 +- .../data/chapter/ChapterRepositoryImpl.kt | 26 +++- .../sqldelight/tachiyomi/data/chapters.sq | 14 +- .../tachiyomi/data/excluded_scanlators.sq | 22 +++ .../sqldelight/tachiyomi/migrations/23.sqm | 2 +- .../sqldelight/tachiyomi/migrations/26.sqm | 44 ++++++ .../sqldelight/tachiyomi/view/libraryView.sq | 4 + .../interactor/GetChaptersByMangaId.kt | 4 +- .../chapter/repository/ChapterRepository.kt | 8 +- .../history/interactor/GetNextChapters.kt | 2 +- .../domain/manga/interactor/FetchInterval.kt | 2 +- .../manga/interactor/GetMangaWithChapters.kt | 8 +- i18n/src/main/res/values/strings.xml | 3 + 26 files changed, 462 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/eu/kanade/domain/chapter/interactor/GetAvailableScanlators.kt create mode 100644 app/src/main/java/eu/kanade/domain/manga/interactor/GetExcludedScanlators.kt create mode 100644 app/src/main/java/eu/kanade/domain/manga/interactor/SetExcludedScanlators.kt create mode 100644 app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt create mode 100644 data/src/main/sqldelight/tachiyomi/data/excluded_scanlators.sq create mode 100644 data/src/main/sqldelight/tachiyomi/migrations/26.sqm diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e3c2aa74f..943d88031 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,7 +22,7 @@ android { defaultConfig { applicationId = "eu.kanade.tachiyomi" - versionCode = 108 + versionCode = 109 versionName = "0.14.7" buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 49c130852..778b7645c 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -1,11 +1,14 @@ package eu.kanade.domain +import eu.kanade.domain.chapter.interactor.GetAvailableScanlators import eu.kanade.domain.chapter.interactor.SetReadStatus import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.download.interactor.DeleteDownload import eu.kanade.domain.extension.interactor.GetExtensionLanguages import eu.kanade.domain.extension.interactor.GetExtensionSources import eu.kanade.domain.extension.interactor.GetExtensionsByType +import eu.kanade.domain.manga.interactor.GetExcludedScanlators +import eu.kanade.domain.manga.interactor.SetExcludedScanlators import eu.kanade.domain.manga.interactor.SetMangaViewerFlags import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.source.interactor.GetEnabledSources @@ -112,6 +115,8 @@ class DomainModule : InjektModule { addFactory { NetworkToLocalManga(get()) } addFactory { UpdateManga(get(), get()) } addFactory { SetMangaCategories(get()) } + addFactory { GetExcludedScanlators(get()) } + addFactory { SetExcludedScanlators(get()) } addSingletonFactory { ReleaseServiceImpl(get(), get()) } addFactory { GetApplicationRelease(get(), get()) } @@ -133,7 +138,8 @@ class DomainModule : InjektModule { addFactory { UpdateChapter(get()) } addFactory { SetReadStatus(get(), get(), get(), get()) } addFactory { ShouldUpdateDbChapter() } - addFactory { SyncChaptersWithSource(get(), get(), get(), get(), get(), get(), get()) } + addFactory { SyncChaptersWithSource(get(), get(), get(), get(), get(), get(), get(), get()) } + addFactory { GetAvailableScanlators(get()) } addSingletonFactory { HistoryRepositoryImpl(get()) } addFactory { GetHistory(get()) } diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/GetAvailableScanlators.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/GetAvailableScanlators.kt new file mode 100644 index 000000000..13bd35e1f --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/GetAvailableScanlators.kt @@ -0,0 +1,24 @@ +package eu.kanade.domain.chapter.interactor + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import tachiyomi.domain.chapter.repository.ChapterRepository + +class GetAvailableScanlators( + private val repository: ChapterRepository, +) { + + private fun List.cleanupAvailableScanlators(): Set { + return mapNotNull { it.ifBlank { null } }.toSet() + } + + suspend fun await(mangaId: Long): Set { + return repository.getScanlatorsByMangaId(mangaId) + .cleanupAvailableScanlators() + } + + fun subscribe(mangaId: Long): Flow> { + return repository.getScanlatorsByMangaIdAsFlow(mangaId) + .map { it.cleanupAvailableScanlators() } + } +} diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt index fd878d5f8..1690180b2 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt @@ -2,6 +2,7 @@ package eu.kanade.domain.chapter.interactor import eu.kanade.domain.chapter.model.copyFromSChapter import eu.kanade.domain.chapter.model.toSChapter +import eu.kanade.domain.manga.interactor.GetExcludedScanlators import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.model.toSManga import eu.kanade.tachiyomi.data.download.DownloadManager @@ -33,6 +34,7 @@ class SyncChaptersWithSource( private val updateManga: UpdateManga, private val updateChapter: UpdateChapter, private val getChaptersByMangaId: GetChaptersByMangaId, + private val getExcludedScanlators: GetExcludedScanlators, ) { /** @@ -208,6 +210,10 @@ class SyncChaptersWithSource( val reAddedUrls = reAdded.map { it.url }.toHashSet() - return updatedToAdd.filterNot { it.url in reAddedUrls } + val excludedScanlators = getExcludedScanlators.await(manga.id).toHashSet() + + return updatedToAdd.filterNot { + it.url in reAddedUrls || it.scanlator in excludedScanlators + } } } diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/GetExcludedScanlators.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/GetExcludedScanlators.kt new file mode 100644 index 000000000..dc326f209 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/GetExcludedScanlators.kt @@ -0,0 +1,24 @@ +package eu.kanade.domain.manga.interactor + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import tachiyomi.data.DatabaseHandler + +class GetExcludedScanlators( + private val handler: DatabaseHandler, +) { + + suspend fun await(mangaId: Long): Set { + return handler.awaitList { + excluded_scanlatorsQueries.getExcludedScanlatorsByMangaId(mangaId) + } + .toSet() + } + + fun subscribe(mangaId: Long): Flow> { + return handler.subscribeToList { + excluded_scanlatorsQueries.getExcludedScanlatorsByMangaId(mangaId) + } + .map { it.toSet() } + } +} diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/SetExcludedScanlators.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/SetExcludedScanlators.kt new file mode 100644 index 000000000..a52fb9afd --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/SetExcludedScanlators.kt @@ -0,0 +1,22 @@ +package eu.kanade.domain.manga.interactor + +import tachiyomi.data.DatabaseHandler + +class SetExcludedScanlators( + private val handler: DatabaseHandler, +) { + + suspend fun await(mangaId: Long, excludedScanlators: Set) { + handler.await(inTransaction = true) { + val currentExcluded = handler.awaitList { + excluded_scanlatorsQueries.getExcludedScanlatorsByMangaId(mangaId) + }.toSet() + val toAdd = excludedScanlators.minus(currentExcluded) + for (scanlator in toAdd) { + excluded_scanlatorsQueries.insert(mangaId, scanlator) + } + val toRemove = currentExcluded.minus(excludedScanlators) + excluded_scanlatorsQueries.remove(mangaId, toRemove) + } + } +} diff --git a/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt index 7370a1449..e29668177 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt @@ -1,13 +1,21 @@ package eu.kanade.presentation.manga +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.PeopleAlt import androidx.compose.material3.AlertDialog import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -15,6 +23,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -29,6 +38,7 @@ import tachiyomi.presentation.core.components.LabeledCheckbox import tachiyomi.presentation.core.components.RadioItem import tachiyomi.presentation.core.components.SortItem import tachiyomi.presentation.core.components.TriStateItem +import tachiyomi.presentation.core.theme.active @Composable fun ChapterSettingsDialog( @@ -37,6 +47,8 @@ fun ChapterSettingsDialog( onDownloadFilterChanged: (TriState) -> Unit, onUnreadFilterChanged: (TriState) -> Unit, onBookmarkedFilterChanged: (TriState) -> Unit, + scanlatorFilterActive: Boolean, + onScanlatorFilterClicked: (() -> Unit), onSortModeChanged: (Long) -> Unit, onDisplayModeChanged: (Long) -> Unit, onSetAsDefault: (applyToExistingManga: Boolean) -> Unit, @@ -89,6 +101,8 @@ fun ChapterSettingsDialog( onUnreadFilterChanged = onUnreadFilterChanged, bookmarkedFilter = manga?.bookmarkedFilter ?: TriState.DISABLED, onBookmarkedFilterChanged = onBookmarkedFilterChanged, + scanlatorFilterActive = scanlatorFilterActive, + onScanlatorFilterClicked = onScanlatorFilterClicked, ) } 1 -> { @@ -117,6 +131,8 @@ private fun ColumnScope.FilterPage( onUnreadFilterChanged: (TriState) -> Unit, bookmarkedFilter: TriState, onBookmarkedFilterChanged: (TriState) -> Unit, + scanlatorFilterActive: Boolean, + onScanlatorFilterClicked: (() -> Unit), ) { TriStateItem( label = stringResource(R.string.label_downloaded), @@ -133,6 +149,39 @@ private fun ColumnScope.FilterPage( state = bookmarkedFilter, onClick = onBookmarkedFilterChanged, ) + ScanlatorFilterItem( + active = scanlatorFilterActive, + onClick = onScanlatorFilterClicked, + ) +} + +@Composable +fun ScanlatorFilterItem( + active: Boolean, + onClick: () -> Unit, +) { + Row( + modifier = Modifier + .clickable(onClick = onClick) + .fillMaxWidth() + .padding(horizontal = TabbedDialogPaddings.Horizontal, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(24.dp), + ) { + Icon( + imageVector = Icons.Outlined.PeopleAlt, + contentDescription = null, + tint = if (active) { + MaterialTheme.colorScheme.active + } else { + LocalContentColor.current + }, + ) + Text( + text = stringResource(R.string.scanlator), + style = MaterialTheme.typography.bodyMedium, + ) + } } @Composable 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 698db525b..6d5ebc39e 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -48,7 +48,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.util.fastAll import androidx.compose.ui.util.fastAny import androidx.compose.ui.util.fastMap -import eu.kanade.domain.manga.model.chaptersFiltered import eu.kanade.presentation.manga.components.ChapterDownloadAction import eu.kanade.presentation.manga.components.ChapterHeader import eu.kanade.presentation.manga.components.ExpandableMangaDescription @@ -308,7 +307,7 @@ private fun MangaScreenSmallImpl( title = state.manga.title, titleAlphaProvider = { animatedTitleAlpha }, backgroundAlphaProvider = { animatedBgAlpha }, - hasFilters = state.manga.chaptersFiltered(), + hasFilters = state.filterActive, onBackClicked = internalOnBackPressed, onClickFilter = onFilterClicked, onClickShare = onShareClicked, @@ -561,7 +560,7 @@ fun MangaScreenLargeImpl( title = state.manga.title, titleAlphaProvider = { if (isAnySelected) 1f else 0f }, backgroundAlphaProvider = { 1f }, - hasFilters = state.manga.chaptersFiltered(), + hasFilters = state.filterActive, onBackClicked = internalOnBackPressed, onClickFilter = onFilterButtonClicked, onClickShare = onShareClicked, diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt new file mode 100644 index 000000000..07d3510d3 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt @@ -0,0 +1,134 @@ +package eu.kanade.presentation.manga.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.CheckBoxOutlineBlank +import androidx.compose.material.icons.rounded.DisabledByDefault +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.minimumInteractiveComponentSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.runtime.toMutableStateList +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.DialogProperties +import eu.kanade.tachiyomi.R +import tachiyomi.presentation.core.components.material.TextButton +import tachiyomi.presentation.core.components.material.padding +import tachiyomi.presentation.core.util.isScrolledToEnd +import tachiyomi.presentation.core.util.isScrolledToStart + +@Composable +fun ScanlatorFilterDialog( + availableScanlators: Set, + excludedScanlators: Set, + onDismissRequest: () -> Unit, + onConfirm: (Set) -> Unit, +) { + val sortedAvailableScanlators = remember(availableScanlators) { + availableScanlators.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it }) + } + val mutableExcludedScanlators = remember(excludedScanlators) { excludedScanlators.toMutableStateList() } + AlertDialog( + onDismissRequest = onDismissRequest, + title = { Text(text = stringResource(R.string.exclude_scanlators)) }, + text = textFunc@{ + if (sortedAvailableScanlators.isEmpty()) { + Text(text = stringResource(R.string.no_scanlators_found)) + return@textFunc + } + Box { + val state = rememberLazyListState() + LazyColumn(state = state) { + sortedAvailableScanlators.forEach { scanlator -> + item { + val isExcluded = mutableExcludedScanlators.contains(scanlator) + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .clickable { + if (isExcluded) { + mutableExcludedScanlators.remove(scanlator) + } else { + mutableExcludedScanlators.add(scanlator) + } + } + .minimumInteractiveComponentSize() + .clip(MaterialTheme.shapes.small) + .fillMaxWidth() + .padding(horizontal = MaterialTheme.padding.small), + ) { + Icon( + imageVector = if (isExcluded) { + Icons.Rounded.DisabledByDefault + } else { + Icons.Rounded.CheckBoxOutlineBlank + }, + tint = if (isExcluded) { + MaterialTheme.colorScheme.primary + } else { + LocalContentColor.current + }, + contentDescription = null, + ) + Text( + text = scanlator, + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier.padding(start = 24.dp), + ) + } + } + } + } + if (!state.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter)) + if (!state.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter)) + } + }, + properties = DialogProperties( + usePlatformDefaultWidth = true, + ), + confirmButton = { + FlowRow { + if (sortedAvailableScanlators.isEmpty()) { + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(R.string.action_cancel)) + } + return@FlowRow + } + TextButton(onClick = mutableExcludedScanlators::clear) { + Text(text = stringResource(R.string.action_reset)) + } + Spacer(modifier = Modifier.weight(1f)) + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(R.string.action_cancel)) + } + TextButton( + onClick = { + onConfirm(mutableExcludedScanlators.toSet()) + onDismissRequest() + }, + ) { + Text(text = stringResource(R.string.action_ok)) + } + } + }, + ) +} 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 index 37c9e73f0..402bd0d94 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt @@ -19,6 +19,7 @@ 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.BackupChapter import eu.kanade.tachiyomi.data.backup.models.BackupHistory import eu.kanade.tachiyomi.data.backup.models.BackupManga import eu.kanade.tachiyomi.data.backup.models.BackupPreference @@ -189,10 +190,15 @@ class BackupCreator( // 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 + handler.awaitList { + chaptersQueries.getChaptersByMangaId( + mangaId = manga.id, + applyScanlatorFilter = 0, // false + mapper = backupChapterMapper, + ) } + .takeUnless(List::isEmpty) + ?.let { mangaObject.chapters = it } } // Check if user wants category information in backup 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 0bc2d8b5d..c33b6cd12 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 @@ -414,7 +414,7 @@ class LibraryScreenModel( } suspend fun getNextUnreadChapter(manga: Manga): Chapter? { - return getChaptersByMangaId.await(manga.id).getNextUnread(manga, downloadManager) + return getChaptersByMangaId.await(manga.id, applyScanlatorFilter = true).getNextUnread(manga, downloadManager) } /** 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 a4504e237..0931ea1fe 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 @@ -9,8 +9,10 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.platform.LocalContext @@ -30,6 +32,7 @@ import eu.kanade.presentation.manga.EditCoverAction import eu.kanade.presentation.manga.MangaScreen import eu.kanade.presentation.manga.components.DeleteChaptersDialog import eu.kanade.presentation.manga.components.MangaCoverDialog +import eu.kanade.presentation.manga.components.ScanlatorFilterDialog import eu.kanade.presentation.manga.components.SetIntervalDialog import eu.kanade.presentation.util.AssistContentScreen import eu.kanade.presentation.util.Screen @@ -152,6 +155,8 @@ class MangaScreen( onInvertSelection = screenModel::invertSelection, ) + var showScanlatorsDialog by remember { mutableStateOf(false) } + val onDismissRequest = { screenModel.dismissDialog() } when (val dialog = successState.dialog) { null -> {} @@ -189,6 +194,8 @@ class MangaScreen( onDisplayModeChanged = screenModel::setDisplayMode, onSetAsDefault = screenModel::setCurrentSettingsAsDefault, onResetToDefault = screenModel::resetToDefaultSettings, + scanlatorFilterActive = successState.scanlatorFilterActive, + onScanlatorFilterClicked = { showScanlatorsDialog = true }, ) MangaScreenModel.Dialog.TrackSheet -> { NavigatorAdaptiveSheet( @@ -235,6 +242,15 @@ class MangaScreen( ) } } + + if (showScanlatorsDialog) { + ScanlatorFilterDialog( + availableScanlators = successState.availableScanlators, + excludedScanlators = successState.excludedScanlators, + onDismissRequest = { showScanlatorsDialog = false }, + onConfirm = screenModel::setExcludedScanlators, + ) + } } private fun continueReading(context: Context, unreadChapter: Chapter?) { 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 004414bc5..3f084c916 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 @@ -11,9 +11,13 @@ import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.core.preference.asState import eu.kanade.core.util.addOrRemove import eu.kanade.core.util.insertSeparators +import eu.kanade.domain.chapter.interactor.GetAvailableScanlators import eu.kanade.domain.chapter.interactor.SetReadStatus import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource +import eu.kanade.domain.manga.interactor.GetExcludedScanlators +import eu.kanade.domain.manga.interactor.SetExcludedScanlators import eu.kanade.domain.manga.interactor.UpdateManga +import eu.kanade.domain.manga.model.chaptersFiltered import eu.kanade.domain.manga.model.downloadedFilter import eu.kanade.domain.manga.model.toSManga import eu.kanade.domain.track.interactor.AddTracks @@ -92,6 +96,9 @@ class MangaScreenModel( private val downloadCache: DownloadCache = Injekt.get(), private val getMangaAndChapters: GetMangaWithChapters = Injekt.get(), private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(), + private val getAvailableScanlators: GetAvailableScanlators = Injekt.get(), + private val getExcludedScanlators: GetExcludedScanlators = Injekt.get(), + private val setExcludedScanlators: SetExcludedScanlators = Injekt.get(), private val setMangaChapterFlags: SetMangaChapterFlags = Injekt.get(), private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(), private val setReadStatus: SetReadStatus = Injekt.get(), @@ -154,7 +161,7 @@ class MangaScreenModel( init { screenModelScope.launchIO { combine( - getMangaAndChapters.subscribe(mangaId).distinctUntilChanged(), + getMangaAndChapters.subscribe(mangaId, applyScanlatorFilter = true).distinctUntilChanged(), downloadCache.changes, downloadManager.queueState, ) { mangaAndChapters, _, _ -> mangaAndChapters } @@ -168,11 +175,31 @@ class MangaScreenModel( } } + screenModelScope.launchIO { + getExcludedScanlators.subscribe(mangaId) + .distinctUntilChanged() + .collectLatest { excludedScanlators -> + updateSuccessState { + it.copy(excludedScanlators = excludedScanlators) + } + } + } + + screenModelScope.launchIO { + getAvailableScanlators.subscribe(mangaId) + .distinctUntilChanged() + .collectLatest { availableScanlators -> + updateSuccessState { + it.copy(availableScanlators = availableScanlators) + } + } + } + observeDownloads() screenModelScope.launchIO { val manga = getMangaAndChapters.awaitManga(mangaId) - val chapters = getMangaAndChapters.awaitChapters(mangaId) + val chapters = getMangaAndChapters.awaitChapters(mangaId, applyScanlatorFilter = true) .toChapterListItems(manga) if (!manga.favorite) { @@ -189,6 +216,8 @@ class MangaScreenModel( source = Injekt.get().getOrStub(manga.source), isFromSource = isFromSource, chapters = chapters, + availableScanlators = getAvailableScanlators.await(mangaId), + excludedScanlators = getExcludedScanlators.await(mangaId), isRefreshingData = needRefreshInfo || needRefreshChapter, dialog = null, ) @@ -995,6 +1024,12 @@ class MangaScreenModel( updateSuccessState { it.copy(dialog = Dialog.FullCover) } } + fun setExcludedScanlators(excludedScanlators: Set) { + screenModelScope.launchIO { + setExcludedScanlators.await(mangaId, excludedScanlators) + } + } + sealed interface State { @Immutable data object Loading : State @@ -1005,12 +1040,13 @@ class MangaScreenModel( val source: Source, val isFromSource: Boolean, val chapters: List, + val availableScanlators: Set, + val excludedScanlators: Set, val trackItems: List = emptyList(), val isRefreshingData: Boolean = false, val dialog: Dialog? = null, val hasPromptedToAddBefore: Boolean = false, ) : State { - val processedChapters by lazy { chapters.applyFilters(manga).toList() } @@ -1042,6 +1078,12 @@ class MangaScreenModel( } } + val scanlatorFilterActive: Boolean + get() = excludedScanlators.intersect(availableScanlators).isNotEmpty() + + val filterActive: Boolean + get() = scanlatorFilterActive || manga.chaptersFiltered() + val trackingAvailable: Boolean get() = trackItems.isNotEmpty() 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 6718f6935..47cfa5ef1 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 @@ -147,7 +147,7 @@ class ReaderViewModel @JvmOverloads constructor( */ private val chapterList by lazy { val manga = manga!! - val chapters = runBlocking { getChaptersByMangaId.await(manga.id) } + val chapters = runBlocking { getChaptersByMangaId.await(manga.id, applyScanlatorFilter = true) } val selectedChapter = chapters.find { it.id == chapterId } ?: error("Requested chapter of id $chapterId not found in chapter list") diff --git a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt index 1249c8967..e156726fa 100644 --- a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt @@ -2,6 +2,7 @@ package tachiyomi.data.chapter import kotlinx.coroutines.flow.Flow import logcat.LogPriority +import tachiyomi.core.util.lang.toLong import tachiyomi.core.util.system.logcat import tachiyomi.data.DatabaseHandler import tachiyomi.domain.chapter.model.Chapter @@ -76,8 +77,22 @@ class ChapterRepositoryImpl( } } - override suspend fun getChapterByMangaId(mangaId: Long): List { - return handler.awaitList { chaptersQueries.getChaptersByMangaId(mangaId, ::mapChapter) } + override suspend fun getChapterByMangaId(mangaId: Long, applyScanlatorFilter: Boolean): List { + return handler.awaitList { + chaptersQueries.getChaptersByMangaId(mangaId, applyScanlatorFilter.toLong(), ::mapChapter) + } + } + + override suspend fun getScanlatorsByMangaId(mangaId: Long): List { + return handler.awaitList { + chaptersQueries.getScanlatorsByMangaId(mangaId) { it.orEmpty() } + } + } + + override fun getScanlatorsByMangaIdAsFlow(mangaId: Long): Flow> { + return handler.subscribeToList { + chaptersQueries.getScanlatorsByMangaId(mangaId) { it.orEmpty() } + } } override suspend fun getBookmarkedChaptersByMangaId(mangaId: Long): List { @@ -93,12 +108,9 @@ class ChapterRepositoryImpl( return handler.awaitOneOrNull { chaptersQueries.getChapterById(id, ::mapChapter) } } - override suspend fun getChapterByMangaIdAsFlow(mangaId: Long): Flow> { + override suspend fun getChapterByMangaIdAsFlow(mangaId: Long, applyScanlatorFilter: Boolean): Flow> { return handler.subscribeToList { - chaptersQueries.getChaptersByMangaId( - mangaId, - ::mapChapter, - ) + chaptersQueries.getChaptersByMangaId(mangaId, applyScanlatorFilter.toLong(), ::mapChapter) } } diff --git a/data/src/main/sqldelight/tachiyomi/data/chapters.sq b/data/src/main/sqldelight/tachiyomi/data/chapters.sq index ef2222885..f51856c54 100644 --- a/data/src/main/sqldelight/tachiyomi/data/chapters.sq +++ b/data/src/main/sqldelight/tachiyomi/data/chapters.sq @@ -36,7 +36,19 @@ FROM chapters WHERE _id = :id; getChaptersByMangaId: -SELECT * +SELECT C.* +FROM chapters C +LEFT JOIN excluded_scanlators ES +ON C.manga_id = ES.manga_id +AND C.scanlator = ES.scanlator +WHERE C.manga_id = :mangaId +AND ( + :applyScanlatorFilter = 0 + OR ES.scanlator IS NULL +); + +getScanlatorsByMangaId: +SELECT scanlator FROM chapters WHERE manga_id = :mangaId; diff --git a/data/src/main/sqldelight/tachiyomi/data/excluded_scanlators.sq b/data/src/main/sqldelight/tachiyomi/data/excluded_scanlators.sq new file mode 100644 index 000000000..2af2f4199 --- /dev/null +++ b/data/src/main/sqldelight/tachiyomi/data/excluded_scanlators.sq @@ -0,0 +1,22 @@ +CREATE TABLE excluded_scanlators( + manga_id INTEGER NOT NULL, + scanlator TEXT NOT NULL, + FOREIGN KEY(manga_id) REFERENCES mangas (_id) + ON DELETE CASCADE +); + +CREATE INDEX excluded_scanlators_manga_id_index ON excluded_scanlators(manga_id); + +insert: +INSERT INTO excluded_scanlators(manga_id, scanlator) +VALUES (:mangaId, :scanlator); + +remove: +DELETE FROM excluded_scanlators +WHERE manga_id = :mangaId +AND scanlator IN :scanlators; + +getExcludedScanlatorsByMangaId: +SELECT scanlator +FROM excluded_scanlators +WHERE manga_id = :mangaId; diff --git a/data/src/main/sqldelight/tachiyomi/migrations/23.sqm b/data/src/main/sqldelight/tachiyomi/migrations/23.sqm index 6b2511354..cf80a941e 100644 --- a/data/src/main/sqldelight/tachiyomi/migrations/23.sqm +++ b/data/src/main/sqldelight/tachiyomi/migrations/23.sqm @@ -20,4 +20,4 @@ FROM mangas JOIN chapters ON mangas._id = chapters.manga_id WHERE favorite = 1 AND date_fetch > date_added -ORDER BY date_fetch DESC; \ No newline at end of file +ORDER BY date_fetch DESC; diff --git a/data/src/main/sqldelight/tachiyomi/migrations/26.sqm b/data/src/main/sqldelight/tachiyomi/migrations/26.sqm new file mode 100644 index 000000000..b68ad43ba --- /dev/null +++ b/data/src/main/sqldelight/tachiyomi/migrations/26.sqm @@ -0,0 +1,44 @@ +CREATE TABLE excluded_scanlators( + manga_id INTEGER NOT NULL, + scanlator TEXT NOT NULL, + FOREIGN KEY(manga_id) REFERENCES mangas (_id) + ON DELETE CASCADE +); + +CREATE INDEX excluded_scanlators_manga_id_index ON excluded_scanlators(manga_id); + +DROP VIEW IF EXISTS libraryView; + +CREATE VIEW libraryView AS +SELECT + M.*, + coalesce(C.total, 0) AS totalCount, + coalesce(C.readCount, 0) AS readCount, + coalesce(C.latestUpload, 0) AS latestUpload, + coalesce(C.fetchedAt, 0) AS chapterFetchedAt, + coalesce(C.lastRead, 0) AS lastRead, + coalesce(C.bookmarkCount, 0) AS bookmarkCount, + coalesce(MC.category_id, 0) AS category +FROM mangas M +LEFT JOIN( + SELECT + chapters.manga_id, + count(*) AS total, + sum(read) AS readCount, + coalesce(max(chapters.date_upload), 0) AS latestUpload, + coalesce(max(history.last_read), 0) AS lastRead, + coalesce(max(chapters.date_fetch), 0) AS fetchedAt, + sum(chapters.bookmark) AS bookmarkCount + FROM chapters + LEFT JOIN excluded_scanlators + ON chapters.manga_id = excluded_scanlators.manga_id + AND chapters.scanlator = excluded_scanlators.scanlator + LEFT JOIN history + ON chapters._id = history.chapter_id + WHERE excluded_scanlators.scanlator IS NULL + GROUP BY chapters.manga_id +) AS C +ON M._id = C.manga_id +LEFT JOIN mangas_categories AS MC +ON MC.manga_id = M._id +WHERE M.favorite = 1; diff --git a/data/src/main/sqldelight/tachiyomi/view/libraryView.sq b/data/src/main/sqldelight/tachiyomi/view/libraryView.sq index 4b1468872..0a5d28543 100644 --- a/data/src/main/sqldelight/tachiyomi/view/libraryView.sq +++ b/data/src/main/sqldelight/tachiyomi/view/libraryView.sq @@ -19,8 +19,12 @@ LEFT JOIN( coalesce(max(chapters.date_fetch), 0) AS fetchedAt, sum(chapters.bookmark) AS bookmarkCount FROM chapters + LEFT JOIN excluded_scanlators + ON chapters.manga_id = excluded_scanlators.manga_id + AND chapters.scanlator = excluded_scanlators.scanlator LEFT JOIN history ON chapters._id = history.chapter_id + WHERE excluded_scanlators.scanlator IS NULL GROUP BY chapters.manga_id ) AS C ON M._id = C.manga_id diff --git a/domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChaptersByMangaId.kt b/domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChaptersByMangaId.kt index 6dcc0d32b..66dab15c7 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChaptersByMangaId.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChaptersByMangaId.kt @@ -9,9 +9,9 @@ class GetChaptersByMangaId( private val chapterRepository: ChapterRepository, ) { - suspend fun await(mangaId: Long): List { + suspend fun await(mangaId: Long, applyScanlatorFilter: Boolean = false): List { return try { - chapterRepository.getChapterByMangaId(mangaId) + chapterRepository.getChapterByMangaId(mangaId, applyScanlatorFilter) } catch (e: Exception) { logcat(LogPriority.ERROR, e) emptyList() diff --git a/domain/src/main/java/tachiyomi/domain/chapter/repository/ChapterRepository.kt b/domain/src/main/java/tachiyomi/domain/chapter/repository/ChapterRepository.kt index 22952f9f9..ae4af5106 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/repository/ChapterRepository.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/repository/ChapterRepository.kt @@ -14,13 +14,17 @@ interface ChapterRepository { suspend fun removeChaptersWithIds(chapterIds: List) - suspend fun getChapterByMangaId(mangaId: Long): List + suspend fun getChapterByMangaId(mangaId: Long, applyScanlatorFilter: Boolean = false): List + + suspend fun getScanlatorsByMangaId(mangaId: Long): List + + fun getScanlatorsByMangaIdAsFlow(mangaId: Long): Flow> suspend fun getBookmarkedChaptersByMangaId(mangaId: Long): List suspend fun getChapterById(id: Long): Chapter? - suspend fun getChapterByMangaIdAsFlow(mangaId: Long): Flow> + suspend fun getChapterByMangaIdAsFlow(mangaId: Long, applyScanlatorFilter: Boolean = false): Flow> suspend fun getChapterByUrlAndMangaId(url: String, mangaId: Long): Chapter? } 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 2cbda1bdf..2e7fefc96 100644 --- a/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt +++ b/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt @@ -20,7 +20,7 @@ class GetNextChapters( suspend fun await(mangaId: Long, onlyUnread: Boolean = true): List { val manga = getManga.await(mangaId) ?: return emptyList() - val chapters = getChaptersByMangaId.await(mangaId) + val chapters = getChaptersByMangaId.await(mangaId, applyScanlatorFilter = true) .sortedWith(getChapterSort(manga, sortDescending = false)) return if (onlyUnread) { diff --git a/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt b/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt index 308ed8bf6..0a9124d16 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt @@ -24,7 +24,7 @@ class FetchInterval( } else { window } - val chapters = getChaptersByMangaId.await(manga.id) + val chapters = getChaptersByMangaId.await(manga.id, applyScanlatorFilter = true) val interval = manga.fetchInterval.takeIf { it < 0 } ?: calculateInterval( chapters, dateTime.zone, diff --git a/domain/src/main/java/tachiyomi/domain/manga/interactor/GetMangaWithChapters.kt b/domain/src/main/java/tachiyomi/domain/manga/interactor/GetMangaWithChapters.kt index 189fe5c1a..4fddd8140 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/interactor/GetMangaWithChapters.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/interactor/GetMangaWithChapters.kt @@ -12,10 +12,10 @@ class GetMangaWithChapters( private val chapterRepository: ChapterRepository, ) { - suspend fun subscribe(id: Long): Flow>> { + suspend fun subscribe(id: Long, applyScanlatorFilter: Boolean = false): Flow>> { return combine( mangaRepository.getMangaByIdAsFlow(id), - chapterRepository.getChapterByMangaIdAsFlow(id), + chapterRepository.getChapterByMangaIdAsFlow(id, applyScanlatorFilter), ) { manga, chapters -> Pair(manga, chapters) } @@ -25,7 +25,7 @@ class GetMangaWithChapters( return mangaRepository.getMangaById(id) } - suspend fun awaitChapters(id: Long): List { - return chapterRepository.getChapterByMangaId(id) + suspend fun awaitChapters(id: Long, applyScanlatorFilter: Boolean = false): List { + return chapterRepository.getChapterByMangaId(id, applyScanlatorFilter) } } diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index e7bf21e34..b15ee64e6 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -14,6 +14,7 @@ Tracking Delete downloaded History + Scanlator More @@ -702,6 +703,8 @@ Set as default No chapters found Are you sure? + Exclude scanlators + No scanlators found Tracking From d0bcd30909adaaf086e0bd5b0e8231561c4b9e0e Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sun, 5 Nov 2023 22:06:20 +0600 Subject: [PATCH 57/66] Trim `Chapter` scanlator value (#10108) --- app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt b/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt index a852e1ae1..32d2381b1 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt @@ -22,7 +22,7 @@ fun Chapter.copyFromSChapter(sChapter: SChapter): Chapter { url = sChapter.url, dateUpload = sChapter.date_upload, chapterNumber = sChapter.chapter_number.toDouble(), - scanlator = sChapter.scanlator?.ifBlank { null }, + scanlator = sChapter.scanlator?.ifBlank { null }?.trim(), ) } From 9e67abcc8a1e7ca90c0a92acc563e998a7a99886 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 5 Nov 2023 11:25:08 -0500 Subject: [PATCH 58/66] Add separate default/apply buttons to reading mode/orientation selection dialogs Related to #3453 --- .../reader/OrientationSelectDialog.kt | 41 ++++++--- .../reader/ReadingModeSelectDialog.kt | 38 +++++--- .../reader/appbars/ReaderAppBars.kt | 1 + .../ChapterNavigator.kt | 2 +- .../reader/components/ModeSelectionDialog.kt | 89 +++++++++++++++++++ i18n/src/main/res/values/strings.xml | 2 + 6 files changed, 149 insertions(+), 24 deletions(-) rename app/src/main/java/eu/kanade/presentation/reader/{appbars => components}/ChapterNavigator.kt (99%) create mode 100644 app/src/main/java/eu/kanade/presentation/reader/components/ModeSelectionDialog.kt diff --git a/app/src/main/java/eu/kanade/presentation/reader/OrientationSelectDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/OrientationSelectDialog.kt index 3d0e1143e..9d3b734cb 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/OrientationSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/OrientationSelectDialog.kt @@ -1,22 +1,23 @@ package eu.kanade.presentation.reader -import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.items import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue 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.tooling.preview.PreviewLightDark -import androidx.compose.ui.unit.dp import eu.kanade.domain.manga.model.readerOrientation import eu.kanade.presentation.components.AdaptiveSheet +import eu.kanade.presentation.reader.components.ModeSelectionDialog import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation @@ -24,6 +25,8 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import tachiyomi.presentation.core.components.SettingsIconGrid import tachiyomi.presentation.core.components.material.IconToggleButton +private val ReaderOrientationsWithoutDefault = ReaderOrientation.entries - ReaderOrientation.DEFAULT + @Composable fun OrientationSelectDialog( onDismissRequest: () -> Unit, @@ -50,13 +53,22 @@ private fun DialogContent( orientation: ReaderOrientation, onChangeOrientation: (ReaderOrientation) -> Unit, ) { - Box(modifier = Modifier.padding(vertical = 16.dp)) { + var selected by remember { mutableStateOf(orientation) } + + ModeSelectionDialog( + onUseDefault = { + onChangeOrientation( + ReaderOrientation.DEFAULT, + ) + }.takeIf { orientation != ReaderOrientation.DEFAULT }, + onApply = { onChangeOrientation(selected) }, + ) { SettingsIconGrid(R.string.rotation_type) { - items(ReaderOrientation.entries) { mode -> + items(ReaderOrientationsWithoutDefault) { mode -> IconToggleButton( - checked = mode == orientation, + checked = mode == selected, onCheckedChange = { - onChangeOrientation(mode) + selected = mode }, modifier = Modifier.fillMaxWidth(), imageVector = ImageVector.vectorResource(mode.iconRes), @@ -72,10 +84,17 @@ private fun DialogContent( private fun DialogContentPreview() { TachiyomiTheme { Surface { - DialogContent( - orientation = ReaderOrientation.DEFAULT, - onChangeOrientation = {}, - ) + Column { + DialogContent( + orientation = ReaderOrientation.DEFAULT, + onChangeOrientation = {}, + ) + + DialogContent( + orientation = ReaderOrientation.FREE, + onChangeOrientation = {}, + ) + } } } } 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 e9a669e17..a34d14e5f 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt @@ -1,15 +1,15 @@ package eu.kanade.presentation.reader -import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.items -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource @@ -17,13 +17,15 @@ import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.PreviewLightDark import eu.kanade.domain.manga.model.readingMode import eu.kanade.presentation.components.AdaptiveSheet +import eu.kanade.presentation.reader.components.ModeSelectionDialog import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import tachiyomi.presentation.core.components.SettingsIconGrid import tachiyomi.presentation.core.components.material.IconToggleButton -import tachiyomi.presentation.core.components.material.padding + +private val ReadingModesWithoutDefault = ReadingMode.entries - ReadingMode.DEFAULT @Composable fun ReadingModeSelectDialog( @@ -51,13 +53,18 @@ private fun DialogContent( readingMode: ReadingMode, onChangeReadingMode: (ReadingMode) -> Unit, ) { - Box(modifier = Modifier.padding(vertical = MaterialTheme.padding.medium)) { + var selected by remember { mutableStateOf(readingMode) } + + ModeSelectionDialog( + onUseDefault = { onChangeReadingMode(ReadingMode.DEFAULT) }.takeIf { readingMode != ReadingMode.DEFAULT }, + onApply = { onChangeReadingMode(selected) }, + ) { SettingsIconGrid(R.string.pref_category_reading_mode) { - items(ReadingMode.entries) { mode -> + items(ReadingModesWithoutDefault) { mode -> IconToggleButton( - checked = mode == readingMode, + checked = mode == selected, onCheckedChange = { - onChangeReadingMode(mode) + selected = mode }, modifier = Modifier.fillMaxWidth(), imageVector = ImageVector.vectorResource(mode.iconRes), @@ -73,10 +80,17 @@ private fun DialogContent( private fun DialogContentPreview() { TachiyomiTheme { Surface { - DialogContent( - readingMode = ReadingMode.DEFAULT, - onChangeReadingMode = {}, - ) + Column { + DialogContent( + readingMode = ReadingMode.DEFAULT, + onChangeReadingMode = {}, + ) + + DialogContent( + readingMode = ReadingMode.LEFT_TO_RIGHT, + onChangeReadingMode = {}, + ) + } } } } diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt index de3d0131f..aff4c8c3f 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -23,6 +23,7 @@ import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBarActions +import eu.kanade.presentation.reader.components.ChapterNavigator import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt b/app/src/main/java/eu/kanade/presentation/reader/components/ChapterNavigator.kt similarity index 99% rename from app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt rename to app/src/main/java/eu/kanade/presentation/reader/components/ChapterNavigator.kt index ede1ae332..a2a3a5c78 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/components/ChapterNavigator.kt @@ -1,4 +1,4 @@ -package eu.kanade.presentation.reader.appbars +package eu.kanade.presentation.reader.components import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource diff --git a/app/src/main/java/eu/kanade/presentation/reader/components/ModeSelectionDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/components/ModeSelectionDialog.kt new file mode 100644 index 000000000..045155b69 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/reader/components/ModeSelectionDialog.kt @@ -0,0 +1,89 @@ +package eu.kanade.presentation.reader.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Check +import androidx.compose.material3.FilledTonalButton +import androidx.compose.material3.Icon +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewLightDark +import androidx.compose.ui.unit.dp +import eu.kanade.presentation.theme.TachiyomiTheme +import eu.kanade.tachiyomi.R +import tachiyomi.presentation.core.components.SettingsItemsPaddings + +@Composable +fun ModeSelectionDialog( + onApply: () -> Unit, + onUseDefault: (() -> Unit)? = null, + content: @Composable () -> Unit, +) { + Box(modifier = Modifier.padding(vertical = 16.dp)) { + Column { + content() + + Row( + modifier = Modifier.padding( + horizontal = SettingsItemsPaddings.Horizontal, + ), + ) { + onUseDefault?.let { + OutlinedButton(onClick = it) { + Text(text = stringResource(R.string.action_revert_to_default)) + } + } + + Spacer(modifier = Modifier.weight(1f)) + + FilledTonalButton( + onClick = onApply, + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = Icons.Outlined.Check, + contentDescription = null, + ) + Text(text = stringResource(R.string.action_apply)) + } + } + } + } + } +} + +@PreviewLightDark +@Composable +private fun Preview() { + TachiyomiTheme { + Surface { + Column { + ModeSelectionDialog( + onApply = {}, + onUseDefault = {}, + ) { + Text("Dummy content") + } + + ModeSelectionDialog( + onApply = {}, + ) { + Text("Dummy content without default") + } + } + } + } +} diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index b15ee64e6..0a9c92a55 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -128,6 +128,7 @@ Disable Pin Unpin + Apply Cancel OK Cancel all @@ -147,6 +148,7 @@ Share Save Reset + Revert to default Undo Close From 3a8aa3e8cd7b725ee73b7fe67d0b1c3111af977b Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 5 Nov 2023 11:52:05 -0500 Subject: [PATCH 59/66] Group mode dialogs together in bottom reader bar --- .../presentation/reader/appbars/BottomReaderBar.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt index 041f68c5e..726095a53 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt @@ -46,6 +46,13 @@ fun BottomReaderBar( ) } + IconButton(onClick = onClickOrientation) { + Icon( + painter = painterResource(orientation.iconRes), + contentDescription = stringResource(R.string.rotation_type), + ) + } + IconButton(onClick = onClickCropBorder) { Icon( painter = painterResource(if (cropEnabled) R.drawable.ic_crop_24dp else R.drawable.ic_crop_off_24dp), @@ -53,13 +60,6 @@ fun BottomReaderBar( ) } - IconButton(onClick = onClickOrientation) { - Icon( - painter = painterResource(orientation.iconRes), - contentDescription = stringResource(R.string.pref_rotation_type), - ) - } - IconButton(onClick = onClickSettings) { Icon( imageVector = Icons.Outlined.Settings, From 9d974273afa1b086af214c20c372541347aed651 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 5 Nov 2023 14:23:36 -0500 Subject: [PATCH 60/66] Update dependency org.junit.jupiter:junit-jupiter to v5.10.1 (#10109) 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 919ac9ce4..b39dd7792 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -82,7 +82,7 @@ sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-ext sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" } sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" } -junit = "org.junit.jupiter:junit-jupiter:5.10.0" +junit = "org.junit.jupiter:junit-jupiter:5.10.1" kotest-assertions = "io.kotest:kotest-assertions-core:5.8.0" mockk = "io.mockk:mockk:1.13.8" From 8f22480ec9f1fa69777e9326879490aa33225ed5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 5 Nov 2023 15:20:42 -0500 Subject: [PATCH 61/66] Update voyager to v1.0.0-rc09 (#10110) 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 b39dd7792..d5f12a1da 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ shizuku_version = "12.2.0" sqlite = "2.4.0" sqldelight = "2.0.0" leakcanary = "2.12" -voyager = "1.0.0-rc08" +voyager = "1.0.0-rc09" richtext = "0.17.0" [libraries] From d7442d771b92b4d1b1c0c762ea6473cb58ece544 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 6 Nov 2023 02:20:54 +0600 Subject: [PATCH 62/66] ScanlatorFilterDialog: Fix crash when no scanlator (#10111) --- .../manga/components/ScanlatorFilterDialog.kt | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt index 07d3510d3..dd19e1361 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/ScanlatorFilterDialog.kt @@ -106,27 +106,27 @@ fun ScanlatorFilterDialog( usePlatformDefaultWidth = true, ), confirmButton = { - FlowRow { - if (sortedAvailableScanlators.isEmpty()) { - TextButton(onClick = onDismissRequest) { - Text(text = stringResource(R.string.action_cancel)) - } - return@FlowRow - } - TextButton(onClick = mutableExcludedScanlators::clear) { - Text(text = stringResource(R.string.action_reset)) - } - Spacer(modifier = Modifier.weight(1f)) + if (sortedAvailableScanlators.isEmpty()) { TextButton(onClick = onDismissRequest) { Text(text = stringResource(R.string.action_cancel)) } - TextButton( - onClick = { - onConfirm(mutableExcludedScanlators.toSet()) - onDismissRequest() - }, - ) { - Text(text = stringResource(R.string.action_ok)) + } else { + FlowRow { + TextButton(onClick = mutableExcludedScanlators::clear) { + Text(text = stringResource(R.string.action_reset)) + } + Spacer(modifier = Modifier.weight(1f)) + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(R.string.action_cancel)) + } + TextButton( + onClick = { + onConfirm(mutableExcludedScanlators.toSet()) + onDismissRequest() + }, + ) { + Text(text = stringResource(R.string.action_ok)) + } } } }, From 634ceeec50b09da25726d74c5dea6657133e1de5 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Mon, 6 Nov 2023 02:21:01 +0600 Subject: [PATCH 63/66] Trim scanlator of chapters in db (#10112) --- data/src/main/sqldelight/tachiyomi/migrations/27.sqm | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 data/src/main/sqldelight/tachiyomi/migrations/27.sqm diff --git a/data/src/main/sqldelight/tachiyomi/migrations/27.sqm b/data/src/main/sqldelight/tachiyomi/migrations/27.sqm new file mode 100644 index 000000000..0d2638594 --- /dev/null +++ b/data/src/main/sqldelight/tachiyomi/migrations/27.sqm @@ -0,0 +1,3 @@ +UPDATE chapters +SET scanlator = trim(scanlator) +WHERE scanlator IS NOT NULL; From 00b2853d3daaa49a2b3bcada1596e094e8da5156 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 5 Nov 2023 17:13:51 -0500 Subject: [PATCH 64/66] Convert create backup dialog to a screen Allows us more flexibility in adding more options/explanations in the future. --- .../settings/screen/SettingsDataScreen.kt | 135 +------------- .../screen/data/CreateBackupScreen.kt | 168 ++++++++++++++++++ .../tachiyomi/data/backup/BackupConst.kt | 24 --- .../data/backup/BackupCreateFlags.kt | 17 ++ .../tachiyomi/data/backup/BackupCreateJob.kt | 2 +- .../tachiyomi/data/backup/BackupCreator.kt | 32 ++-- i18n/src/main/res/values/strings.xml | 3 +- .../core/components/LabeledCheckbox.kt | 2 + 8 files changed, 209 insertions(+), 174 deletions(-) create mode 100644 app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateFlags.kt diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt index c62c6c12a..b6a866f3d 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt @@ -1,6 +1,5 @@ package eu.kanade.presentation.more.settings.screen -import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent import android.net.Uri @@ -13,11 +12,9 @@ import androidx.annotation.StringRes import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.AlertDialog -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -27,41 +24,34 @@ import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.runtime.toMutableStateList -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.more.settings.Preference +import eu.kanade.presentation.more.settings.screen.data.CreateBackupScreen import eu.kanade.presentation.more.settings.widget.BasePreferenceWidget import eu.kanade.presentation.more.settings.widget.PrefsHorizontalPadding import eu.kanade.presentation.permissions.PermissionRequestHelper import eu.kanade.presentation.util.relativeTimeSpanString import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.backup.BackupConst import eu.kanade.tachiyomi.data.backup.BackupCreateJob import eu.kanade.tachiyomi.data.backup.BackupFileValidator import eu.kanade.tachiyomi.data.backup.BackupRestoreJob -import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.toast -import kotlinx.coroutines.launch import logcat.LogPriority import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.system.logcat import tachiyomi.domain.backup.service.BackupPreferences import tachiyomi.domain.library.service.LibraryPreferences -import tachiyomi.presentation.core.components.LabeledCheckbox -import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.util.collectAsState -import tachiyomi.presentation.core.util.isScrolledToEnd -import tachiyomi.presentation.core.util.isScrolledToStart import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -131,124 +121,11 @@ object SettingsDataScreen : SearchableSettings { @Composable private fun getCreateBackupPref(): Preference.PreferenceItem.TextPreference { - val scope = rememberCoroutineScope() - val context = LocalContext.current - - var flag by rememberSaveable { mutableIntStateOf(0) } - val chooseBackupDir = rememberLauncherForActivityResult( - contract = ActivityResultContracts.CreateDocument("application/*"), - ) { - if (it != null) { - context.contentResolver.takePersistableUriPermission( - it, - Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION, - ) - BackupCreateJob.startNow(context, it, flag) - } - flag = 0 - } - var showCreateDialog by rememberSaveable { mutableStateOf(false) } - if (showCreateDialog) { - CreateBackupDialog( - onConfirm = { - showCreateDialog = false - flag = it - try { - chooseBackupDir.launch(Backup.getFilename()) - } catch (e: ActivityNotFoundException) { - flag = 0 - context.toast(R.string.file_picker_error) - } - }, - onDismissRequest = { showCreateDialog = false }, - ) - } - + val navigator = LocalNavigator.currentOrThrow return Preference.PreferenceItem.TextPreference( title = stringResource(R.string.pref_create_backup), subtitle = stringResource(R.string.pref_create_backup_summ), - onClick = { - scope.launch { - if (!BackupCreateJob.isManualJobRunning(context)) { - if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) { - context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG) - } - showCreateDialog = true - } else { - context.toast(R.string.backup_in_progress) - } - } - }, - ) - } - - @Composable - private fun CreateBackupDialog( - onConfirm: (flag: Int) -> Unit, - onDismissRequest: () -> Unit, - ) { - val choices = remember { - mapOf( - BackupConst.BACKUP_CATEGORY to R.string.categories, - 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, - BackupConst.BACKUP_SOURCE_PREFS to R.string.source_settings, - ) - } - val flags = remember { choices.keys.toMutableStateList() } - AlertDialog( - onDismissRequest = onDismissRequest, - title = { Text(text = stringResource(R.string.backup_choice)) }, - text = { - Box { - val state = rememberLazyListState() - ScrollbarLazyColumn(state = state) { - item { - LabeledCheckbox( - label = stringResource(R.string.manga), - checked = true, - onCheckedChange = {}, - ) - } - choices.forEach { (k, v) -> - item { - val isSelected = flags.contains(k) - LabeledCheckbox( - label = stringResource(v), - checked = isSelected, - onCheckedChange = { - if (it) { - flags.add(k) - } else { - flags.remove(k) - } - }, - ) - } - } - } - if (!state.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter)) - if (!state.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter)) - } - }, - dismissButton = { - TextButton(onClick = onDismissRequest) { - Text(text = stringResource(R.string.action_cancel)) - } - }, - confirmButton = { - TextButton( - onClick = { - val flag = flags.fold(initial = 0, operation = { a, b -> a or b }) - onConfirm(flag) - }, - ) { - Text(text = stringResource(R.string.action_ok)) - } - }, + onClick = { navigator.push(CreateBackupScreen()) }, ) } @@ -336,7 +213,7 @@ object SettingsDataScreen : SearchableSettings { }, ) { if (it == null) { - error = InvalidRestore(message = context.getString(R.string.file_null_uri_error)) + context.toast(R.string.file_null_uri_error) return@rememberLauncherForActivityResult } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt new file mode 100644 index 000000000..571a7bda8 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt @@ -0,0 +1,168 @@ +package eu.kanade.presentation.more.settings.screen.data + +import android.content.ActivityNotFoundException +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.widget.Toast +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Button +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import cafe.adriel.voyager.core.model.StateScreenModel +import cafe.adriel.voyager.core.model.rememberScreenModel +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import eu.kanade.presentation.components.AppBar +import eu.kanade.presentation.util.Screen +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags +import eu.kanade.tachiyomi.data.backup.BackupCreateJob +import eu.kanade.tachiyomi.data.backup.models.Backup +import eu.kanade.tachiyomi.util.system.DeviceUtil +import eu.kanade.tachiyomi.util.system.toast +import kotlinx.coroutines.flow.update +import tachiyomi.presentation.core.components.LabeledCheckbox +import tachiyomi.presentation.core.components.material.Scaffold +import tachiyomi.presentation.core.components.material.padding + +class CreateBackupScreen : Screen() { + + @Composable + override fun Content() { + val context = LocalContext.current + val navigator = LocalNavigator.currentOrThrow + val model = rememberScreenModel { CreateBackupScreenModel() } + val state by model.state.collectAsState() + + val chooseBackupDir = rememberLauncherForActivityResult( + contract = ActivityResultContracts.CreateDocument("application/*"), + ) { + if (it != null) { + context.contentResolver.takePersistableUriPermission( + it, + Intent.FLAG_GRANT_READ_URI_PERMISSION or + Intent.FLAG_GRANT_WRITE_URI_PERMISSION, + ) + model.createBackup(context, it) + navigator.pop() + } + } + + Scaffold( + topBar = { + AppBar( + title = stringResource(R.string.pref_create_backup), + navigateUp = navigator::pop, + scrollBehavior = it, + ) + }, + ) { contentPadding -> + Column( + modifier = Modifier + .padding(contentPadding) + .fillMaxSize(), + ) { + LazyColumn( + modifier = Modifier + .weight(1f) + .padding(horizontal = MaterialTheme.padding.medium), + ) { + item { + LabeledCheckbox( + label = stringResource(R.string.manga), + checked = true, + onCheckedChange = {}, + enabled = false, + ) + } + BackupChoices.forEach { (k, v) -> + item { + LabeledCheckbox( + label = stringResource(v), + checked = state.flags.contains(k), + onCheckedChange = { + model.toggleFlag(k) + }, + ) + } + } + } + + HorizontalDivider() + + Button( + modifier = Modifier + .padding(horizontal = 16.dp, vertical = 8.dp) + .fillMaxWidth(), + onClick = { + if (!BackupCreateJob.isManualJobRunning(context)) { + if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) { + context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG) + } + try { + chooseBackupDir.launch(Backup.getFilename()) + } catch (e: ActivityNotFoundException) { + context.toast(R.string.file_picker_error) + } + } else { + context.toast(R.string.backup_in_progress) + } + }, + ) { + Text( + text = stringResource(R.string.action_create), + color = MaterialTheme.colorScheme.onPrimary, + ) + } + } + } + } +} + +private class CreateBackupScreenModel : StateScreenModel(State()) { + + fun toggleFlag(flag: Int) { + mutableState.update { + if (it.flags.contains(flag)) { + it.copy(flags = it.flags - flag) + } else { + it.copy(flags = it.flags + flag) + } + } + } + + fun createBackup(context: Context, uri: Uri) { + val flags = state.value.flags.fold(initial = 0, operation = { a, b -> a or b }) + BackupCreateJob.startNow(context, uri, flags) + } + + @Immutable + data class State( + val flags: Set = BackupChoices.keys, + ) +} + +private val BackupChoices = mapOf( + BackupCreateFlags.BACKUP_CATEGORY to R.string.categories, + BackupCreateFlags.BACKUP_CHAPTER to R.string.chapters, + BackupCreateFlags.BACKUP_TRACK to R.string.track, + BackupCreateFlags.BACKUP_HISTORY to R.string.history, + BackupCreateFlags.BACKUP_APP_PREFS to R.string.app_settings, + BackupCreateFlags.BACKUP_SOURCE_PREFS to R.string.source_settings, +) 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 deleted file mode 100644 index 6bc4771dc..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt +++ /dev/null @@ -1,24 +0,0 @@ -package eu.kanade.tachiyomi.data.backup - -// Filter options -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_APP_PREFS = 0x10 - const val BACKUP_APP_PREFS_MASK = 0x10 - - 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/BackupCreateFlags.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateFlags.kt new file mode 100644 index 000000000..7ae6edfde --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateFlags.kt @@ -0,0 +1,17 @@ +package eu.kanade.tachiyomi.data.backup + +internal object BackupCreateFlags { + const val BACKUP_CATEGORY = 0x1 + const val BACKUP_CHAPTER = 0x2 + const val BACKUP_HISTORY = 0x4 + const val BACKUP_TRACK = 0x8 + const val BACKUP_APP_PREFS = 0x10 + const val BACKUP_SOURCE_PREFS = 0x20 + + const val AutomaticDefaults = BACKUP_CATEGORY or + BACKUP_CHAPTER or + BACKUP_HISTORY or + BACKUP_TRACK or + BACKUP_APP_PREFS or + BACKUP_SOURCE_PREFS +} 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 d46a58e00..4226e77fc 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 @@ -41,7 +41,7 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete val backupPreferences = Injekt.get() val uri = inputData.getString(LOCATION_URI_KEY)?.toUri() ?: backupPreferences.backupsDirectory().get().toUri() - val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupConst.BACKUP_ALL) + val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupCreateFlags.AutomaticDefaults) try { setForeground(getForegroundInfo()) 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 index 402bd0d94..a843a3b0c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt @@ -5,18 +5,12 @@ 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.BackupCreateFlags.BACKUP_APP_PREFS +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CATEGORY +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CHAPTER +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_HISTORY +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_SOURCE_PREFS +import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_TRACK import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.backup.models.BackupCategory import eu.kanade.tachiyomi.data.backup.models.BackupChapter @@ -161,7 +155,7 @@ class BackupCreator( */ private suspend fun backupCategories(options: Int): List { // Check if user wants category information in backup - return if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) { + return if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) { getCategories.await() .filterNot(Category::isSystemCategory) .map(backupCategoryMapper) @@ -188,7 +182,7 @@ class BackupCreator( val mangaObject = BackupManga.copyFrom(manga) // Check if user wants chapter information in backup - if (options and BACKUP_CHAPTER_MASK == BACKUP_CHAPTER) { + if (options and BACKUP_CHAPTER == BACKUP_CHAPTER) { // Backup all the chapters handler.awaitList { chaptersQueries.getChaptersByMangaId( @@ -202,7 +196,7 @@ class BackupCreator( } // Check if user wants category information in backup - if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) { + if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) { // Backup categories for this manga val categoriesForManga = getCategories.await(manga.id) if (categoriesForManga.isNotEmpty()) { @@ -211,7 +205,7 @@ class BackupCreator( } // Check if user wants track information in backup - if (options and BACKUP_TRACK_MASK == BACKUP_TRACK) { + if (options and BACKUP_TRACK == BACKUP_TRACK) { val tracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id, backupTrackMapper) } if (tracks.isNotEmpty()) { mangaObject.tracking = tracks @@ -219,7 +213,7 @@ class BackupCreator( } // Check if user wants history information in backup - if (options and BACKUP_HISTORY_MASK == BACKUP_HISTORY) { + if (options and BACKUP_HISTORY == BACKUP_HISTORY) { val historyByMangaId = getHistory.await(manga.id) if (historyByMangaId.isNotEmpty()) { val history = historyByMangaId.map { history -> @@ -236,13 +230,13 @@ class BackupCreator( } private fun backupAppPreferences(flags: Int): List { - if (flags and BACKUP_APP_PREFS_MASK != BACKUP_APP_PREFS) return emptyList() + if (flags and BACKUP_APP_PREFS != 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() + if (flags and BACKUP_SOURCE_PREFS != BACKUP_SOURCE_PREFS) return emptyList() return sourceManager.getCatalogueSources() .filterIsInstance() diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 0a9c92a55..47b7a9efa 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -484,6 +484,7 @@ Backup location Automatic backup frequency Maximum automatic backups + Create Backup created Invalid backup file Backup does not contain any library entries. @@ -880,7 +881,7 @@ Select cover image Select backup file No file picker app found - File picker failed to return file to app + No file selected Download diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/LabeledCheckbox.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/LabeledCheckbox.kt index 0a72e4b0b..f2039cd36 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/LabeledCheckbox.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/LabeledCheckbox.kt @@ -21,6 +21,7 @@ fun LabeledCheckbox( label: String, checked: Boolean, onCheckedChange: (Boolean) -> Unit, + enabled: Boolean = true, ) { Row( modifier = modifier @@ -37,6 +38,7 @@ fun LabeledCheckbox( Checkbox( checked = checked, onCheckedChange = null, + enabled = enabled, ) Text(text = label) From 58b2895ec910ecd6557cf7d6fb27fbb4bccecda1 Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 8 Nov 2023 09:20:23 -0500 Subject: [PATCH 65/66] Update to Compose Compiler 1.5.4 and Kotlin 1.9.20 --- gradle/compose.versions.toml | 2 +- gradle/kotlinx.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 26f0809d0..492bc2c38 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,5 +1,5 @@ [versions] -compiler = "1.5.3" +compiler = "1.5.4" compose-bom = "2023.09.00-alpha02" accompanist = "0.33.1-alpha" diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index 1f7a93033..fb63cc85e 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -1,5 +1,5 @@ [versions] -kotlin_version = "1.9.10" +kotlin_version = "1.9.20" serialization_version = "1.6.0" xml_serialization_version = "0.86.2" From 402e2c47fb549f98392b7155a6beed5a53b73f97 Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 8 Nov 2023 22:08:19 -0500 Subject: [PATCH 66/66] Fix EmptyScreen kaomoji looking broken for RTL locales --- .../presentation/core/screens/EmptyScreen.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/screens/EmptyScreen.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/screens/EmptyScreen.kt index c3a0cbe79..23eaa436c 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/screens/EmptyScreen.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/screens/EmptyScreen.kt @@ -12,12 +12,15 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEach import tachiyomi.presentation.core.components.ActionButton @@ -59,11 +62,13 @@ fun EmptyScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Text( - text = face, - modifier = Modifier.secondaryItemAlpha(), - style = MaterialTheme.typography.displayMedium, - ) + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + Text( + text = face, + modifier = Modifier.secondaryItemAlpha(), + style = MaterialTheme.typography.displayMedium, + ) + } Text( text = message,