From 97b4d1f13de194163d7dc13a0d73d023109bc8c2 Mon Sep 17 00:00:00 2001 From: arkon Date: Mon, 9 Oct 2023 22:27:46 -0400 Subject: [PATCH 01/37] Use Compose to animate bottom reader menu bars --- .../tachiyomi/ui/reader/ReaderActivity.kt | 147 +++++++++--------- app/src/main/res/anim/enter_from_bottom.xml | 8 - app/src/main/res/anim/exit_to_bottom.xml | 8 - 3 files changed, 75 insertions(+), 88 deletions(-) delete mode 100644 app/src/main/res/anim/enter_from_bottom.xml delete mode 100644 app/src/main/res/anim/exit_to_bottom.xml 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 4d09abb55..365ee46d5 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 @@ -24,6 +24,10 @@ import android.view.animation.Animation import android.view.animation.AnimationUtils import android.widget.Toast import androidx.activity.viewModels +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -249,7 +253,7 @@ class ReaderActivity : BaseActivity() { override fun onResume() { super.onResume() viewModel.restartReadTimer() - setMenuVisibility(viewModel.state.value.menuVisible, animate = false) + setMenuVisibility(viewModel.state.value.menuVisible) } /** @@ -259,7 +263,7 @@ class ReaderActivity : BaseActivity() { override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) if (hasFocus) { - setMenuVisibility(viewModel.state.value.menuVisible, animate = false) + setMenuVisibility(viewModel.state.value.menuVisible) } } @@ -473,43 +477,55 @@ class ReaderActivity : BaseActivity() { val isPagerType = ReadingModeType.isPagerType(viewModel.getMangaReadingMode()) val cropEnabled = if (isPagerType) cropBorderPaged else cropBorderWebtoon - Column( - verticalArrangement = Arrangement.spacedBy(8.dp), + AnimatedVisibility( + visible = state.menuVisible, + enter = slideInVertically( + initialOffsetY = { it }, + animationSpec = tween(200), + ), + exit = slideOutVertically( + targetOffsetY = { it }, + animationSpec = tween(200), + ), ) { - ChapterNavigator( - isRtl = isRtl, - onNextChapter = ::loadNextChapter, - enabledNext = state.viewerChapters?.nextChapter != null, - onPreviousChapter = ::loadPreviousChapter, - enabledPrevious = state.viewerChapters?.prevChapter != null, - currentPage = state.currentPage, - totalPages = state.totalPages, - onSliderValueChange = { - isScrollingThroughPages = true - moveToPageIndex(it) - }, - ) + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + ChapterNavigator( + isRtl = isRtl, + onNextChapter = ::loadNextChapter, + enabledNext = state.viewerChapters?.nextChapter != null, + onPreviousChapter = ::loadPreviousChapter, + enabledPrevious = state.viewerChapters?.prevChapter != null, + currentPage = state.currentPage, + totalPages = state.totalPages, + onSliderValueChange = { + isScrollingThroughPages = true + moveToPageIndex(it) + }, + ) - BottomReaderBar( - readingMode = ReadingModeType.fromPreference(viewModel.getMangaReadingMode(resolveDefault = false)), - onClickReadingMode = viewModel::openReadingModeSelectDialog, - orientationMode = OrientationType.fromPreference(viewModel.getMangaOrientationType(resolveDefault = false)), - onClickOrientationMode = viewModel::openOrientationModeSelectDialog, - cropEnabled = cropEnabled, - onClickCropBorder = { - val enabled = viewModel.toggleCropBorders() + BottomReaderBar( + readingMode = ReadingModeType.fromPreference(viewModel.getMangaReadingMode(resolveDefault = false)), + onClickReadingMode = viewModel::openReadingModeSelectDialog, + orientationMode = OrientationType.fromPreference(viewModel.getMangaOrientationType(resolveDefault = false)), + onClickOrientationMode = viewModel::openOrientationModeSelectDialog, + cropEnabled = cropEnabled, + onClickCropBorder = { + val enabled = viewModel.toggleCropBorders() - menuToggleToast?.cancel() - menuToggleToast = toast( - if (enabled) { - R.string.on - } else { - R.string.off - }, - ) - }, - onClickSettings = viewModel::openSettingsDialog, - ) + menuToggleToast?.cancel() + menuToggleToast = toast( + if (enabled) { + R.string.on + } else { + R.string.off + }, + ) + }, + onClickSettings = viewModel::openSettingsDialog, + ) + } } } @@ -531,54 +547,41 @@ class ReaderActivity : BaseActivity() { } /** - * Sets the visibility of the menu according to [visible] and with an optional parameter to - * [animate] the views. + * Sets the visibility of the menu according to [visible]. */ - private fun setMenuVisibility(visible: Boolean, animate: Boolean = true) { + private fun setMenuVisibility(visible: Boolean) { viewModel.showMenus(visible) if (visible) { windowInsetsController.show(WindowInsetsCompat.Type.systemBars()) binding.readerMenu.isVisible = true - if (animate) { - val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top) - toolbarAnimation.applySystemAnimatorScale(this) - toolbarAnimation.setAnimationListener( - object : SimpleAnimationListener() { - override fun onAnimationStart(animation: Animation) { - // Fix status bar being translucent the first time it's opened. - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) - } - }, - ) - binding.toolbar.startAnimation(toolbarAnimation) - - val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_bottom) - bottomAnimation.applySystemAnimatorScale(this) - binding.readerMenuBottom.startAnimation(bottomAnimation) - } + val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top) + toolbarAnimation.applySystemAnimatorScale(this) + toolbarAnimation.setAnimationListener( + object : SimpleAnimationListener() { + override fun onAnimationStart(animation: Animation) { + // Fix status bar being translucent the first time it's opened. + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) + } + }, + ) + binding.toolbar.startAnimation(toolbarAnimation) } else { if (readerPreferences.fullscreen().get()) { windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE } - if (animate) { - val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_top) - toolbarAnimation.applySystemAnimatorScale(this) - toolbarAnimation.setAnimationListener( - object : SimpleAnimationListener() { - override fun onAnimationEnd(animation: Animation) { - binding.readerMenu.isVisible = false - } - }, - ) - binding.toolbar.startAnimation(toolbarAnimation) - - val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_bottom) - bottomAnimation.applySystemAnimatorScale(this) - binding.readerMenuBottom.startAnimation(bottomAnimation) - } + val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_top) + toolbarAnimation.applySystemAnimatorScale(this) + toolbarAnimation.setAnimationListener( + object : SimpleAnimationListener() { + override fun onAnimationEnd(animation: Animation) { + binding.readerMenu.isVisible = false + } + }, + ) + binding.toolbar.startAnimation(toolbarAnimation) } } diff --git a/app/src/main/res/anim/enter_from_bottom.xml b/app/src/main/res/anim/enter_from_bottom.xml deleted file mode 100644 index c9bd492a5..000000000 --- a/app/src/main/res/anim/enter_from_bottom.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/anim/exit_to_bottom.xml b/app/src/main/res/anim/exit_to_bottom.xml deleted file mode 100644 index d5d94c795..000000000 --- a/app/src/main/res/anim/exit_to_bottom.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file From 90d3dd22426bbf1b398026a28e4cb4d552e6f435 Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 12 Oct 2023 22:15:30 -0400 Subject: [PATCH 02/37] Use relative touch positions for reader tap events Fixes #10004 --- .../ui/reader/viewer/GestureDetectorWithLongTap.kt | 6 +++--- .../kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt | 2 +- .../tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/GestureDetectorWithLongTap.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/GestureDetectorWithLongTap.kt index a85f8dc7d..50c687a33 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/GestureDetectorWithLongTap.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/GestureDetectorWithLongTap.kt @@ -41,13 +41,13 @@ open class GestureDetectorWithLongTap( // This is the key difference with the built-in detector. We have to ignore the // event if the last up and current down are too close in time (double tap). if (ev.downTime - lastUp > doubleTapTime) { - downX = ev.rawX - downY = ev.rawY + downX = ev.x + downY = ev.y handler.postDelayed(longTapFn, longTapTime) } } MotionEvent.ACTION_MOVE -> { - if (abs(ev.rawX - downX) > slop || abs(ev.rawY - downY) > slop) { + if (abs(ev.x - downX) > slop || abs(ev.y - downY) > slop) { handler.removeCallbacks(longTapFn) } } 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 de23ee9e6..71ec13ffb 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 @@ -102,7 +102,7 @@ abstract class PagerViewer(val activity: ReaderActivity) : Viewer { }, ) pager.tapListener = { event -> - val pos = PointF(event.rawX / pager.width, event.rawY / pager.height) + val pos = PointF(event.x / pager.width, event.y / pager.height) when (config.navigator.getAction(pos)) { NavigationRegion.MENU -> activity.toggleMenu() NavigationRegion.NEXT -> moveToNext() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index d85a5b04b..d54432b6b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -111,7 +111,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr }, ) recycler.tapListener = { event -> - val pos = PointF(event.rawX / recycler.width, event.rawY / recycler.height) + val pos = PointF(event.x / recycler.width, event.y / recycler.height) when (config.navigator.getAction(pos)) { NavigationRegion.MENU -> activity.toggleMenu() NavigationRegion.NEXT, NavigationRegion.RIGHT -> scrollDown() From 7c012010558d5e7a2ea32a8aaef3c908fdc52799 Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 12 Oct 2023 22:42:49 -0400 Subject: [PATCH 03/37] Refactor reader bottom bar to presentation package --- .../reader/{ => appbars}/BottomReaderBar.kt | 2 +- .../reader/{ => appbars}/ChapterNavigator.kt | 2 +- .../reader/appbars/ReaderAppBars.kt | 88 +++++++++++++ .../tachiyomi/ui/reader/ReaderActivity.kt | 124 +++++++----------- app/src/main/res/layout/reader_activity.xml | 6 - 5 files changed, 141 insertions(+), 81 deletions(-) rename app/src/main/java/eu/kanade/presentation/reader/{ => appbars}/BottomReaderBar.kt (98%) rename app/src/main/java/eu/kanade/presentation/reader/{ => appbars}/ChapterNavigator.kt (99%) create mode 100644 app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt diff --git a/app/src/main/java/eu/kanade/presentation/reader/BottomReaderBar.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt similarity index 98% rename from app/src/main/java/eu/kanade/presentation/reader/BottomReaderBar.kt rename to app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt index e88692ff0..ec6acdd78 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/BottomReaderBar.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt @@ -1,4 +1,4 @@ -package eu.kanade.presentation.reader +package eu.kanade.presentation.reader.appbars import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme diff --git a/app/src/main/java/eu/kanade/presentation/reader/ChapterNavigator.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt similarity index 99% rename from app/src/main/java/eu/kanade/presentation/reader/ChapterNavigator.kt rename to app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt index 6432b8e1b..31a9a905f 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ChapterNavigator.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ChapterNavigator.kt @@ -1,4 +1,4 @@ -package eu.kanade.presentation.reader +package eu.kanade.presentation.reader.appbars import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource 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 new file mode 100644 index 000000000..1bd4d54ac --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -0,0 +1,88 @@ +package eu.kanade.presentation.reader.appbars + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import eu.kanade.tachiyomi.ui.reader.setting.OrientationType +import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType +import eu.kanade.tachiyomi.ui.reader.viewer.Viewer +import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer + +private val animationSpec = tween(200) + +@Composable +fun ReaderAppBars( + visible: Boolean, + viewer: Viewer?, + + onNextChapter: () -> Unit, + enabledNext: Boolean, + onPreviousChapter: () -> Unit, + enabledPrevious: Boolean, + currentPage: Int, + totalPages: Int, + onSliderValueChange: (Int) -> Unit, + + readingMode: ReadingModeType, + onClickReadingMode: () -> Unit, + orientationMode: OrientationType, + onClickOrientationMode: () -> Unit, + cropEnabled: Boolean, + onClickCropBorder: () -> Unit, + onClickSettings: () -> Unit, +) { + val isRtl = viewer is R2LPagerViewer + + Column( + modifier = Modifier.fillMaxHeight(), + verticalArrangement = Arrangement.SpaceBetween, + ) { + Spacer(modifier = Modifier.weight(1f)) + + AnimatedVisibility( + visible = visible, + enter = slideInVertically( + initialOffsetY = { it }, + animationSpec = animationSpec, + ), + exit = slideOutVertically( + targetOffsetY = { it }, + animationSpec = animationSpec, + ), + ) { + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + ChapterNavigator( + isRtl = isRtl, + onNextChapter = onNextChapter, + enabledNext = enabledNext, + onPreviousChapter = onPreviousChapter, + enabledPrevious = enabledPrevious, + currentPage = currentPage, + totalPages = totalPages, + onSliderValueChange = onSliderValueChange, + ) + + BottomReaderBar( + readingMode = readingMode, + onClickReadingMode = onClickReadingMode, + orientationMode = orientationMode, + onClickOrientationMode = onClickOrientationMode, + cropEnabled = cropEnabled, + onClickCropBorder = onClickCropBorder, + onClickSettings = onClickSettings, + ) + } + } + } +} 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 365ee46d5..8f855a32f 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 @@ -24,12 +24,7 @@ import android.view.animation.Animation import android.view.animation.AnimationUtils import android.widget.Toast import androidx.activity.viewModels -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.tween -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.material3.AlertDialog import androidx.compose.material3.CircularProgressIndicator @@ -54,12 +49,11 @@ import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.transition.platform.MaterialContainerTransform import dev.chrisbanes.insetter.applyInsetter import eu.kanade.domain.base.BasePreferences -import eu.kanade.presentation.reader.BottomReaderBar -import eu.kanade.presentation.reader.ChapterNavigator import eu.kanade.presentation.reader.OrientationModeSelectDialog import eu.kanade.presentation.reader.PageIndicatorText import eu.kanade.presentation.reader.ReaderPageActionsDialog import eu.kanade.presentation.reader.ReadingModeSelectDialog +import eu.kanade.presentation.reader.appbars.ReaderAppBars import eu.kanade.presentation.reader.settings.ReaderSettingsDialog import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.notification.NotificationReceiver @@ -79,7 +73,6 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator -import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer import eu.kanade.tachiyomi.ui.webview.WebViewActivity import eu.kanade.tachiyomi.util.system.applySystemAnimatorScale import eu.kanade.tachiyomi.util.system.hasDisplayCutout @@ -366,9 +359,9 @@ class ReaderActivity : BaseActivity() { margin(top = true, horizontal = true) } } - binding.readerMenuBottom.applyInsetter { + binding.dialogRoot.applyInsetter { type(navigationBars = true) { - margin(bottom = true, horizontal = true) + margin(vertical = true, horizontal = true) } } @@ -407,6 +400,54 @@ class ReaderActivity : BaseActivity() { ) } + val cropBorderPaged by readerPreferences.cropBorders().collectAsState() + val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() + val isPagerType = ReadingModeType.isPagerType(viewModel.getMangaReadingMode()) + val cropEnabled = if (isPagerType) cropBorderPaged else cropBorderWebtoon + + ReaderAppBars( + visible = state.menuVisible, + viewer = state.viewer, + + onNextChapter = ::loadNextChapter, + enabledNext = state.viewerChapters?.nextChapter != null, + onPreviousChapter = ::loadPreviousChapter, + enabledPrevious = state.viewerChapters?.prevChapter != null, + currentPage = state.currentPage, + totalPages = state.totalPages, + onSliderValueChange = { + isScrollingThroughPages = true + moveToPageIndex(it) + }, + + readingMode = ReadingModeType.fromPreference( + viewModel.getMangaReadingMode( + resolveDefault = false, + ), + ), + onClickReadingMode = viewModel::openReadingModeSelectDialog, + orientationMode = OrientationType.fromPreference( + viewModel.getMangaOrientationType( + resolveDefault = false, + ), + ), + onClickOrientationMode = viewModel::openOrientationModeSelectDialog, + cropEnabled = cropEnabled, + onClickCropBorder = { + val enabled = viewModel.toggleCropBorders() + + menuToggleToast?.cancel() + menuToggleToast = toast( + if (enabled) { + R.string.on + } else { + R.string.off + }, + ) + }, + onClickSettings = viewModel::openSettingsDialog, + ) + val onDismissRequest = viewModel::closeDialog when (state.dialog) { is ReaderViewModel.Dialog.Loading -> { @@ -466,69 +507,6 @@ class ReaderActivity : BaseActivity() { } } - binding.readerMenuBottom.setComposeContent { - val state by viewModel.state.collectAsState() - - if (state.viewer == null) return@setComposeContent - val isRtl = state.viewer is R2LPagerViewer - - val cropBorderPaged by readerPreferences.cropBorders().collectAsState() - val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() - val isPagerType = ReadingModeType.isPagerType(viewModel.getMangaReadingMode()) - val cropEnabled = if (isPagerType) cropBorderPaged else cropBorderWebtoon - - AnimatedVisibility( - visible = state.menuVisible, - enter = slideInVertically( - initialOffsetY = { it }, - animationSpec = tween(200), - ), - exit = slideOutVertically( - targetOffsetY = { it }, - animationSpec = tween(200), - ), - ) { - Column( - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - ChapterNavigator( - isRtl = isRtl, - onNextChapter = ::loadNextChapter, - enabledNext = state.viewerChapters?.nextChapter != null, - onPreviousChapter = ::loadPreviousChapter, - enabledPrevious = state.viewerChapters?.prevChapter != null, - currentPage = state.currentPage, - totalPages = state.totalPages, - onSliderValueChange = { - isScrollingThroughPages = true - moveToPageIndex(it) - }, - ) - - BottomReaderBar( - readingMode = ReadingModeType.fromPreference(viewModel.getMangaReadingMode(resolveDefault = false)), - onClickReadingMode = viewModel::openReadingModeSelectDialog, - orientationMode = OrientationType.fromPreference(viewModel.getMangaOrientationType(resolveDefault = false)), - onClickOrientationMode = viewModel::openOrientationModeSelectDialog, - cropEnabled = cropEnabled, - onClickCropBorder = { - val enabled = viewModel.toggleCropBorders() - - menuToggleToast?.cancel() - menuToggleToast = toast( - if (enabled) { - R.string.on - } else { - R.string.off - }, - ) - }, - onClickSettings = viewModel::openSettingsDialog, - ) - } - } - } - val toolbarBackground = (binding.toolbar.background as MaterialShapeDrawable).apply { elevation = resources.getDimension(R.dimen.m3_sys_elevation_level2) alpha = if (isNightMode()) 230 else 242 // 90% dark 95% light diff --git a/app/src/main/res/layout/reader_activity.xml b/app/src/main/res/layout/reader_activity.xml index b7e34e987..ac9b535b0 100644 --- a/app/src/main/res/layout/reader_activity.xml +++ b/app/src/main/res/layout/reader_activity.xml @@ -56,12 +56,6 @@ android:layout_height="wrap_content" android:minHeight="?attr/actionBarSize" /> - - Date: Thu, 12 Oct 2023 22:43:03 -0400 Subject: [PATCH 04/37] Minor cleanup --- .../kanade/tachiyomi/data/backup/BackupCreator.kt | 2 +- .../eu/kanade/tachiyomi/ui/main/MainActivity.kt | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) 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 b70df331f..ef8704b02 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 @@ -238,7 +238,7 @@ class BackupCreator( private fun backupSourcePreferences(flags: Int): List { if (flags and BACKUP_SOURCE_PREFS_MASK != BACKUP_SOURCE_PREFS) return emptyList() - return sourceManager.getOnlineSources() + return sourceManager.getCatalogueSources() .filterIsInstance() .map { BackupSourcePreferences( 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 7b07c8521..a7b3b9ce4 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 @@ -89,6 +89,7 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import logcat.LogPriority import tachiyomi.core.Constants +import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.system.logcat import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.release.interactor.GetApplicationRelease @@ -279,7 +280,9 @@ class MainActivity : BaseActivity() { setSplashScreenExitAnimation(splashScreen) if (isLaunch && libraryPreferences.autoClearChapterCache().get()) { - chapterCache.clear() + lifecycleScope.launchIO { + chapterCache.clear() + } } } @@ -436,13 +439,13 @@ class MainActivity : BaseActivity() { } companion object { - // Splash screen - private const val SPLASH_MIN_DURATION = 500 // ms - private const val SPLASH_MAX_DURATION = 5000 // ms - private const val SPLASH_EXIT_ANIM_DURATION = 400L // ms - const val INTENT_SEARCH = "eu.kanade.tachiyomi.SEARCH" const val INTENT_SEARCH_QUERY = "query" const val INTENT_SEARCH_FILTER = "filter" } } + +// Splash screen +private const val SPLASH_MIN_DURATION = 500 // ms +private const val SPLASH_MAX_DURATION = 5000 // ms +private const val SPLASH_EXIT_ANIM_DURATION = 400L // ms From 540fb1bb7c36fda0b6c070caacd8fb2a4176ddc0 Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 12 Oct 2023 22:49:21 -0400 Subject: [PATCH 05/37] Use AppBar abstraction in more places --- .../presentation/category/CategoryScreen.kt | 24 +++---------------- .../more/settings/PreferenceScaffold.kt | 17 ++++--------- .../settings/screen/SettingsMainScreen.kt | 20 ++++------------ .../about/OpenSourceLibraryLicenseScreen.kt | 22 +++-------------- .../screen/debug/BackupSchemaScreen.kt | 14 +++-------- .../settings/screen/debug/WorkerInfoScreen.kt | 14 +++-------- .../details/SourcePreferencesScreen.kt | 15 ++++-------- 7 files changed, 24 insertions(+), 102 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt b/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt index 3e3364d79..485d3e4ff 100644 --- a/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt @@ -8,17 +8,11 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material.icons.outlined.SortByAlpha -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import eu.kanade.presentation.category.components.CategoryFloatingActionButton import eu.kanade.presentation.category.components.CategoryListItem import eu.kanade.presentation.components.AppBar @@ -46,21 +40,9 @@ fun CategoryScreen( val lazyListState = rememberLazyListState() Scaffold( topBar = { scrollBehavior -> - TopAppBar( - title = { - Text( - text = stringResource(R.string.action_edit_categories), - modifier = Modifier.padding(start = 8.dp), - ) - }, - navigationIcon = { - IconButton(onClick = navigateUp) { - Icon( - imageVector = Icons.Outlined.ArrowBack, - contentDescription = stringResource(R.string.abc_action_bar_up_description), - ) - } - }, + AppBar( + title = stringResource(R.string.action_edit_categories), + navigateUp = navigateUp, actions = { AppBarActions( listOf( diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScaffold.kt b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScaffold.kt index fb9a3de2a..7db293379 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScaffold.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceScaffold.kt @@ -2,12 +2,9 @@ package eu.kanade.presentation.more.settings import androidx.annotation.StringRes import androidx.compose.foundation.layout.RowScope -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource -import eu.kanade.presentation.components.UpIcon +import eu.kanade.presentation.components.AppBar import tachiyomi.presentation.core.components.material.Scaffold @Composable @@ -19,15 +16,9 @@ fun PreferenceScaffold( ) { Scaffold( topBar = { - TopAppBar( - title = { Text(text = stringResource(titleRes)) }, - navigationIcon = { - if (onBackPressed != null) { - IconButton(onClick = onBackPressed) { - UpIcon() - } - } - }, + AppBar( + title = stringResource(titleRes), + navigateUp = onBackPressed, actions = actions, scrollBehavior = it, ) 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 513acc39b..86cb2790d 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 @@ -20,11 +20,8 @@ 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.Sync -import androidx.compose.material3.IconButton import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable @@ -44,7 +41,6 @@ import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBarActions -import eu.kanade.presentation.components.UpIcon import eu.kanade.presentation.more.settings.screen.about.AboutScreen import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget import eu.kanade.presentation.util.LocalBackPress @@ -82,21 +78,13 @@ object SettingsMainScreen : Screen() { val backPress = LocalBackPress.currentOrThrow val containerColor = if (twoPane) getPalerSurface() else MaterialTheme.colorScheme.surface val topBarState = rememberTopAppBarState() + Scaffold( topBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(topBarState), topBar = { scrollBehavior -> - TopAppBar( - title = { - Text( - text = stringResource(R.string.label_settings), - modifier = Modifier.padding(start = 8.dp), - ) - }, - navigationIcon = { - IconButton(onClick = backPress::invoke) { - UpIcon() - } - }, + AppBar( + title = stringResource(R.string.label_settings), + navigateUp = backPress::invoke, actions = { AppBarActions( listOf( diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLibraryLicenseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLibraryLicenseScreen.kt index 992f267a8..964f503b0 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLibraryLicenseScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLibraryLicenseScreen.kt @@ -5,17 +5,11 @@ 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.filled.ArrowBack import androidx.compose.material.icons.filled.Public -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.core.text.HtmlCompat @@ -41,19 +35,9 @@ class OpenSourceLibraryLicenseScreen( Scaffold( topBar = { - TopAppBar( - title = { - Text( - text = name, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - }, - navigationIcon = { - IconButton(onClick = navigator::pop) { - Icon(imageVector = Icons.Default.ArrowBack, contentDescription = null) - } - }, + AppBar( + title = name, + navigateUp = navigator::pop, actions = { if (!website.isNullOrEmpty()) { AppBarActions( diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt index bc8905050..4c4d22a69 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt @@ -4,12 +4,8 @@ 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.filled.ArrowBack import androidx.compose.material.icons.filled.ContentCopy -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier @@ -43,13 +39,9 @@ class BackupSchemaScreen : Screen() { Scaffold( topBar = { - TopAppBar( - title = { Text(text = title) }, - navigationIcon = { - IconButton(onClick = navigator::pop) { - Icon(imageVector = Icons.Default.ArrowBack, contentDescription = null) - } - }, + AppBar( + title = title, + navigateUp = navigator::pop, actions = { AppBarActions( listOf( 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 ff318a9b4..e7e815df6 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 @@ -7,13 +7,9 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.rememberScrollState import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.ContentCopy -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -61,13 +57,9 @@ class WorkerInfoScreen : Screen() { Scaffold( topBar = { - TopAppBar( - title = { Text(text = title) }, - navigationIcon = { - IconButton(onClick = navigator::pop) { - Icon(imageVector = Icons.Default.ArrowBack, contentDescription = null) - } - }, + AppBar( + title = title, + navigateUp = navigator::pop, actions = { AppBarActions( listOf( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/SourcePreferencesScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/SourcePreferencesScreen.kt index 4e391cb3e..b4c1321c0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/SourcePreferencesScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/SourcePreferencesScreen.kt @@ -7,9 +7,6 @@ import android.view.View import androidx.appcompat.view.ContextThemeWrapper import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf @@ -34,7 +31,7 @@ import androidx.preference.forEach import androidx.preference.getOnBindEditTextListener import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow -import eu.kanade.presentation.components.UpIcon +import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.SharedPreferencesDataStore @@ -55,13 +52,9 @@ class SourcePreferencesScreen(val sourceId: Long) : Screen() { Scaffold( topBar = { - TopAppBar( - title = { Text(text = Injekt.get().getOrStub(sourceId).toString()) }, - navigationIcon = { - IconButton(onClick = navigator::pop) { - UpIcon() - } - }, + AppBar( + title = Injekt.get().getOrStub(sourceId).toString(), + navigateUp = navigator::pop, scrollBehavior = it, ) }, From c386d375dee2a846dd59395e6eda3a07311ed3d5 Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 12 Oct 2023 22:56:19 -0400 Subject: [PATCH 06/37] Tweak Cloudflare help message in WebView screen Catches pages like what Shinigami is currently showing. Also adjusts the banner to make it look more like part of the top AppBar so it looks less like part of the webpage. --- .../settings/screen/SettingsMainScreen.kt | 2 +- .../webview/WebViewScreenContent.kt | 169 ++++++++++-------- 2 files changed, 91 insertions(+), 80 deletions(-) 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 86cb2790d..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 @@ -78,7 +78,7 @@ object SettingsMainScreen : Screen() { val backPress = LocalBackPress.currentOrThrow val containerColor = if (twoPane) getPalerSurface() else MaterialTheme.colorScheme.surface val topBarState = rememberTopAppBarState() - + Scaffold( topBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(topBarState), topBar = { scrollBehavior -> 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 5f88a4fe3..04133bc49 100644 --- a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt +++ b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt @@ -7,6 +7,7 @@ import android.webkit.WebView import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box 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.material.icons.Icons @@ -14,6 +15,8 @@ import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material.icons.outlined.ArrowForward import androidx.compose.material.icons.outlined.Close import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -22,8 +25,10 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import com.google.accompanist.web.AccompanistWebViewClient import com.google.accompanist.web.LoadingState import com.google.accompanist.web.WebView @@ -72,7 +77,7 @@ fun WebViewScreenContent( super.onPageFinished(view, url) scope.launch { val html = view.getHtml() - showCloudflareHelp = "window._cf_chl_opt" in html + showCloudflareHelp = "window._cf_chl_opt" in html || "Ray ID is" in html } } @@ -103,54 +108,71 @@ fun WebViewScreenContent( Scaffold( topBar = { Box { - AppBar( - title = state.pageTitle ?: initialTitle, - subtitle = currentUrl, - navigateUp = onNavigateUp, - navigationIcon = Icons.Outlined.Close, - actions = { - AppBarActions( - listOf( - AppBar.Action( - title = stringResource(R.string.action_webview_back), - icon = Icons.Outlined.ArrowBack, - onClick = { - if (navigator.canGoBack) { - navigator.navigateBack() - } + Column { + AppBar( + title = state.pageTitle ?: initialTitle, + subtitle = currentUrl, + navigateUp = onNavigateUp, + navigationIcon = Icons.Outlined.Close, + actions = { + AppBarActions( + listOf( + AppBar.Action( + title = stringResource(R.string.action_webview_back), + icon = Icons.Outlined.ArrowBack, + onClick = { + if (navigator.canGoBack) { + navigator.navigateBack() + } + }, + enabled = navigator.canGoBack, + ), + AppBar.Action( + title = stringResource(R.string.action_webview_forward), + icon = Icons.Outlined.ArrowForward, + onClick = { + if (navigator.canGoForward) { + navigator.navigateForward() + } + }, + enabled = navigator.canGoForward, + ), + AppBar.OverflowAction( + title = stringResource(R.string.action_webview_refresh), + onClick = { navigator.reload() }, + ), + AppBar.OverflowAction( + title = stringResource(R.string.action_share), + onClick = { onShare(currentUrl) }, + ), + AppBar.OverflowAction( + title = stringResource(R.string.action_open_in_browser), + onClick = { onOpenInBrowser(currentUrl) }, + ), + AppBar.OverflowAction( + title = stringResource(R.string.pref_clear_cookies), + onClick = { onClearCookies(currentUrl) }, + ), + ), + ) + }, + ) + + if (showCloudflareHelp) { + Surface( + modifier = Modifier.padding(8.dp), + ) { + WarningBanner( + textRes = R.string.information_cloudflare_help, + modifier = Modifier + .clip(MaterialTheme.shapes.small) + .clickable { + uriHandler.openUri("https://tachiyomi.org/docs/guides/troubleshooting/#cloudflare") }, - enabled = navigator.canGoBack, - ), - AppBar.Action( - title = stringResource(R.string.action_webview_forward), - icon = Icons.Outlined.ArrowForward, - onClick = { - if (navigator.canGoForward) { - navigator.navigateForward() - } - }, - enabled = navigator.canGoForward, - ), - AppBar.OverflowAction( - title = stringResource(R.string.action_webview_refresh), - onClick = { navigator.reload() }, - ), - AppBar.OverflowAction( - title = stringResource(R.string.action_share), - onClick = { onShare(currentUrl) }, - ), - AppBar.OverflowAction( - title = stringResource(R.string.action_open_in_browser), - onClick = { onOpenInBrowser(currentUrl) }, - ), - AppBar.OverflowAction( - title = stringResource(R.string.pref_clear_cookies), - onClick = { onClearCookies(currentUrl) }, - ), - ), - ) - }, - ) + ) + } + } + } when (val loadingState = state.loadingState) { is LoadingState.Initializing -> LinearProgressIndicator( modifier = Modifier @@ -168,38 +190,27 @@ fun WebViewScreenContent( } }, ) { contentPadding -> - Column( - modifier = Modifier.padding(contentPadding), - ) { - if (showCloudflareHelp) { - WarningBanner( - textRes = R.string.information_cloudflare_help, - modifier = Modifier.clickable { - uriHandler.openUri("https://tachiyomi.org/docs/guides/troubleshooting/#cloudflare") - }, - ) - } + WebView( + state = state, + modifier = Modifier + .fillMaxSize() + .padding(contentPadding), + navigator = navigator, + onCreated = { webView -> + webView.setDefaultSettings() - WebView( - state = state, - modifier = Modifier.weight(1f), - navigator = navigator, - onCreated = { webView -> - webView.setDefaultSettings() + // Debug mode (chrome://inspect/#devices) + if (BuildConfig.DEBUG && + 0 != webView.context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE + ) { + WebView.setWebContentsDebuggingEnabled(true) + } - // Debug mode (chrome://inspect/#devices) - if (BuildConfig.DEBUG && - 0 != webView.context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE - ) { - WebView.setWebContentsDebuggingEnabled(true) - } - - headers["user-agent"]?.let { - webView.settings.userAgentString = it - } - }, - client = webClient, - ) - } + headers["user-agent"]?.let { + webView.settings.userAgentString = it + } + }, + client = webClient, + ) } } From c492efcb31775a65464cf68b4a249bc5bb8e6016 Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Fri, 13 Oct 2023 10:04:40 +0700 Subject: [PATCH 07/37] ExtensionLoader: Set read-only to private extension files (#10007) --- .../extension/util/ExtensionLoader.kt | 4 +- .../tachiyomi/util/storage/FileExtensions.kt | 38 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt index f6ab9f577..28161fcb3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt @@ -14,6 +14,7 @@ import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceFactory import eu.kanade.tachiyomi.util.lang.Hash +import eu.kanade.tachiyomi.util.storage.copyAndSetReadOnlyTo import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.runBlocking @@ -97,7 +98,8 @@ internal object ExtensionLoader { val target = File(getPrivateExtensionDir(context), "${extension.packageName}.$PRIVATE_EXTENSION_EXTENSION") return try { - file.copyTo(target, overwrite = true) + file.delete() + file.copyAndSetReadOnlyTo(target, overwrite = true) if (currentExtension != null) { ExtensionInstallReceiver.notifyReplaced(context, extension.packageName) } else { 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 b939eb301..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 @@ -23,3 +23,41 @@ fun File.getUriCompat(context: Context): Uri { this.toUri() } } + +/** + * Copies this file to the given [target] file while marking the file as read-only. + * + * @see File.copyTo + */ +fun File.copyAndSetReadOnlyTo(target: File, overwrite: Boolean = false, bufferSize: Int = DEFAULT_BUFFER_SIZE): File { + if (!this.exists()) { + throw NoSuchFileException(file = this, reason = "The source file doesn't exist.") + } + + if (target.exists()) { + if (!overwrite) { + 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.") + } + } + + if (this.isDirectory) { + if (!target.mkdirs()) { + throw FileSystemException(file = this, other = target, reason = "Failed to create target directory.") + } + } else { + target.parentFile?.mkdirs() + + this.inputStream().use { input -> + target.outputStream().use { output -> + // Set read-only + target.setReadOnly() + + input.copyTo(output, bufferSize) + } + } + } + + return target +} From 0026f96fadbe029e8419985e69fb63bd2fe16d7f Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Sat, 14 Oct 2023 21:52:04 +0700 Subject: [PATCH 08/37] MangaSummary: Refactor to not use SubcomposeLayout (#10008) --- .../manga/components/MangaInfoHeader.kt | 109 +++++++++--------- 1 file changed, 55 insertions(+), 54 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 4d9e320fe..35e0997e2 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 @@ -48,7 +48,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable @@ -63,9 +62,8 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.layout.SubcomposeLayout +import androidx.compose.ui.layout.Layout import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign @@ -589,67 +587,70 @@ private fun MangaSummary( expanded: Boolean, modifier: Modifier = Modifier, ) { - var expandedHeight by remember { mutableIntStateOf(0) } - var shrunkHeight by remember { mutableIntStateOf(0) } - val heightDelta = remember(expandedHeight, shrunkHeight) { expandedHeight - shrunkHeight } val animProgress by animateFloatAsState(if (expanded) 1f else 0f) - val scrimHeight = with(LocalDensity.current) { remember { 24.sp.roundToPx() } } - - SubcomposeLayout(modifier = modifier.clipToBounds()) { constraints -> - val shrunkPlaceable = subcompose("description-s") { - Text( - text = "\n\n", // Shows at least 3 lines - style = MaterialTheme.typography.bodyMedium, - ) - }.map { it.measure(constraints) } - shrunkHeight = shrunkPlaceable.maxByOrNull { it.height }?.height ?: 0 - - val expandedPlaceable = subcompose("description-l") { - Text( - text = expandedDescription, - style = MaterialTheme.typography.bodyMedium, - ) - }.map { it.measure(constraints) } - expandedHeight = expandedPlaceable.maxByOrNull { it.height }?.height?.coerceAtLeast(shrunkHeight) ?: 0 - - val actualPlaceable = subcompose("description") { - SelectionContainer { + Layout( + modifier = modifier.clipToBounds(), + contents = listOf( + { Text( - text = if (expanded) expandedDescription else shrunkDescription, - maxLines = Int.MAX_VALUE, + text = "\n\n", // Shows at least 3 lines style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onBackground, - modifier = Modifier.secondaryItemAlpha(), ) - } - }.map { it.measure(constraints) } + }, + { + Text( + text = expandedDescription, + style = MaterialTheme.typography.bodyMedium, + ) + }, + { + SelectionContainer { + Text( + text = if (expanded) expandedDescription else shrunkDescription, + maxLines = Int.MAX_VALUE, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onBackground, + modifier = Modifier.secondaryItemAlpha(), + ) + } + }, + { + val colors = listOf(Color.Transparent, MaterialTheme.colorScheme.background) + Box( + modifier = Modifier.background(Brush.verticalGradient(colors = colors)), + contentAlignment = Alignment.Center, + ) { + 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), + tint = MaterialTheme.colorScheme.onBackground, + modifier = Modifier.background(Brush.radialGradient(colors = colors.asReversed())), + ) + } + }, + ), + ) { (shrunk, expanded, actual, scrim), constraints -> + val shrunkHeight = shrunk.single() + .measure(constraints) + .height + val expandedHeight = expanded.single() + .measure(constraints) + .height + val heightDelta = expandedHeight - shrunkHeight + val scrimHeight = 24.dp.roundToPx() - val scrimPlaceable = subcompose("scrim") { - val colors = listOf(Color.Transparent, MaterialTheme.colorScheme.background) - Box( - modifier = Modifier.background(Brush.verticalGradient(colors = colors)), - contentAlignment = Alignment.Center, - ) { - 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), - tint = MaterialTheme.colorScheme.onBackground, - modifier = Modifier.background(Brush.radialGradient(colors = colors.asReversed())), - ) - } - }.map { it.measure(Constraints.fixed(width = constraints.maxWidth, height = scrimHeight)) } + val actualPlaceable = actual.single() + .measure(constraints) + val scrimPlaceable = scrim.single() + .measure(Constraints.fixed(width = constraints.maxWidth, height = scrimHeight)) val currentHeight = shrunkHeight + ((heightDelta + scrimHeight) * animProgress).roundToInt() layout(constraints.maxWidth, currentHeight) { - actualPlaceable.forEach { - it.place(0, 0) - } + actualPlaceable.place(0, 0) val scrimY = currentHeight - scrimHeight - scrimPlaceable.forEach { - it.place(0, scrimY) - } + scrimPlaceable.place(0, scrimY) } } } From 8a7bbfddda232a86e7a9051466782539d3a6acd0 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 14 Oct 2023 11:09:11 -0400 Subject: [PATCH 09/37] Add info about formatting task in CONTRIBUTING.md [skip ci] --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 15d4d1b3a..81e69f498 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,6 +24,10 @@ Before you start, please note that the ability to use following technologies is - [Android Studio](https://developer.android.com/studio) - Emulator or phone with developer options enabled to test changes. +## Linting + +To auto-fix some linting errors, run the `ktlintFormat` Gradle task. + ## Getting help - Join [the Discord server](https://discord.gg/tachiyomi) for online help and to ask questions while developing. From 5619a4c0d995774a4ba4e4030f639a62a708b771 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 14 Oct 2023 11:11:05 -0400 Subject: [PATCH 10/37] Remove remaining usages of platform-provided strings --- .../eu/kanade/presentation/manga/ChapterSettingsDialog.kt | 2 +- .../presentation/more/settings/screen/SettingsBackupScreen.kt | 2 +- .../eu/kanade/presentation/track/TrackInfoDialogSelector.kt | 4 ++-- .../eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) 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 8b9ef54a3..7cfcbf053 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt @@ -199,7 +199,7 @@ private fun SetAsDefaultDialog( }, dismissButton = { TextButton(onClick = onDismissRequest) { - Text(text = stringResource(android.R.string.cancel)) + Text(text = stringResource(R.string.action_cancel)) } }, confirmButton = { diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt index ec6b2a1da..5ab8f228a 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt @@ -246,7 +246,7 @@ object SettingsBackupScreen : SearchableSettings { onDismissRequest() }, ) { - Text(text = stringResource(android.R.string.copy)) + Text(text = stringResource(R.string.action_copy_to_clipboard)) } }, confirmButton = { 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 a13112e5e..42ff82007 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt @@ -171,7 +171,7 @@ fun TrackDateSelector( Spacer(modifier = Modifier.weight(1f)) } TextButton(onClick = onDismissRequest) { - Text(text = stringResource(android.R.string.cancel)) + Text(text = stringResource(R.string.action_cancel)) } TextButton(onClick = { onConfirm(pickerState.selectedDateMillis!!) }) { Text(text = stringResource(R.string.action_ok)) @@ -209,7 +209,7 @@ private fun BaseSelector( Spacer(modifier = Modifier.weight(1f)) } TextButton(onClick = onDismissRequest) { - Text(text = stringResource(android.R.string.cancel)) + Text(text = stringResource(R.string.action_cancel)) } TextButton(onClick = onConfirm) { Text(text = stringResource(R.string.action_ok)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index f25dab5c8..6c811b7ad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -593,7 +593,7 @@ private data class TrackDateRemoverScreen( horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small, Alignment.End), ) { TextButton(onClick = navigator::pop) { - Text(text = stringResource(android.R.string.cancel)) + Text(text = stringResource(R.string.action_cancel)) } FilledTonalButton( onClick = { From d18022c25990f1961fef77eabb3924c68f283250 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 14 Oct 2023 12:30:17 -0400 Subject: [PATCH 11/37] Migrate top reader app bar to Compose --- .../kanade/presentation/components/AppBar.kt | 9 +- .../reader/appbars/BottomReaderBar.kt | 10 +- .../reader/appbars/ReaderAppBars.kt | 80 ++++++++- .../tachiyomi/ui/reader/ReaderActivity.kt | 163 +++++------------- .../tachiyomi/ui/reader/ReaderViewModel.kt | 27 ++- .../listener/SimpleAnimationListener.kt | 11 -- app/src/main/res/anim/enter_from_top.xml | 8 - app/src/main/res/anim/exit_to_top.xml | 8 - .../main/res/drawable/ic_bookmark_24dp.xml | 9 - .../res/drawable/ic_bookmark_border_24dp.xml | 9 - app/src/main/res/layout/reader_activity.xml | 17 -- app/src/main/res/menu/reader.xml | 29 ---- 12 files changed, 149 insertions(+), 231 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/widget/listener/SimpleAnimationListener.kt delete mode 100644 app/src/main/res/anim/enter_from_top.xml delete mode 100644 app/src/main/res/anim/exit_to_top.xml delete mode 100644 app/src/main/res/drawable/ic_bookmark_24dp.xml delete mode 100644 app/src/main/res/drawable/ic_bookmark_border_24dp.xml delete mode 100644 app/src/main/res/menu/reader.xml 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 1acd220fc..7ccfae0bd 100644 --- a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt +++ b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt @@ -1,5 +1,6 @@ package eu.kanade.presentation.components +import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.RowScope @@ -60,6 +61,7 @@ const val SEARCH_DEBOUNCE_MILLIS = 250L @Composable fun AppBar( modifier: Modifier = Modifier, + backgroundColor: Color? = null, // Text title: String?, subtitle: String? = null, @@ -81,6 +83,7 @@ fun AppBar( AppBar( modifier = modifier, + backgroundColor = backgroundColor, titleContent = { if (isActionMode) { AppBarTitle(actionModeCounter.toString()) @@ -106,6 +109,7 @@ fun AppBar( @Composable fun AppBar( modifier: Modifier = Modifier, + backgroundColor: Color? = null, // Title titleContent: @Composable () -> Unit, // Up button @@ -142,7 +146,7 @@ fun AppBar( title = titleContent, actions = actions, colors = TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( + containerColor = backgroundColor ?: MaterialTheme.colorScheme.surfaceColorAtElevation( elevation = if (isActionMode) 3.dp else 0.dp, ), ), @@ -170,6 +174,9 @@ fun AppBarTitle( style = MaterialTheme.typography.bodyMedium, maxLines = 1, overflow = TextOverflow.Ellipsis, + modifier = Modifier.basicMarquee( + delayMillis = 2_000, + ), ) } } 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 ec6acdd78..e48867fcb 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 @@ -1,7 +1,6 @@ package eu.kanade.presentation.reader.appbars import androidx.compose.foundation.background -import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -10,11 +9,10 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Settings import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable 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.res.stringResource import androidx.compose.ui.unit.dp @@ -24,6 +22,7 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType @Composable fun BottomReaderBar( + backgroundColor: Color, readingMode: ReadingModeType, onClickReadingMode: () -> Unit, orientationMode: OrientationType, @@ -32,11 +31,6 @@ fun BottomReaderBar( onClickCropBorder: () -> Unit, onClickSettings: () -> Unit, ) { - // Match with toolbar background color set in ReaderActivity - val backgroundColor = MaterialTheme.colorScheme - .surfaceColorAtElevation(3.dp) - .copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f) - Row( modifier = Modifier .fillMaxWidth() 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 1bd4d54ac..1683b2028 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 @@ -4,14 +4,28 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.clickable +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.material.icons.Icons +import androidx.compose.material.icons.outlined.Bookmark +import androidx.compose.material.icons.outlined.BookmarkBorder +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource 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.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.viewer.Viewer @@ -22,8 +36,18 @@ private val animationSpec = tween(200) @Composable fun ReaderAppBars( visible: Boolean, - viewer: Viewer?, + fullscreen: Boolean, + mangaTitle: String?, + chapterTitle: String?, + navigateUp: () -> Unit, + onClickTopAppBar: () -> Unit, + bookmarked: Boolean, + onToggleBookmarked: () -> Unit, + onOpenInWebView: (() -> Unit)?, + onShare: (() -> Unit)?, + + viewer: Viewer?, onNextChapter: () -> Unit, enabledNext: Boolean, onPreviousChapter: () -> Unit, @@ -41,11 +65,64 @@ fun ReaderAppBars( onClickSettings: () -> Unit, ) { val isRtl = viewer is R2LPagerViewer + val backgroundColor = MaterialTheme.colorScheme + .surfaceColorAtElevation(3.dp) + .copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f) + + val appBarModifier = if (fullscreen) { + Modifier.windowInsetsPadding(WindowInsets.systemBars) + } else { + Modifier + } Column( modifier = Modifier.fillMaxHeight(), verticalArrangement = Arrangement.SpaceBetween, ) { + AnimatedVisibility( + visible = visible, + enter = slideInVertically( + initialOffsetY = { -it }, + animationSpec = animationSpec, + ), + exit = slideOutVertically( + targetOffsetY = { -it }, + animationSpec = animationSpec, + ), + ) { + AppBar( + modifier = appBarModifier + .clickable(onClick = onClickTopAppBar), + backgroundColor = backgroundColor, + title = mangaTitle, + subtitle = chapterTitle, + navigateUp = navigateUp, + actions = { + AppBarActions( + listOfNotNull( + AppBar.Action( + 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, + ), + onOpenInWebView?.let { + AppBar.OverflowAction( + title = stringResource(R.string.action_open_in_web_view), + onClick = it, + ) + }, + onShare?.let { + AppBar.OverflowAction( + title = stringResource(R.string.action_share), + onClick = it, + ) + }, + ), + ) + }, + ) + } + Spacer(modifier = Modifier.weight(1f)) AnimatedVisibility( @@ -74,6 +151,7 @@ fun ReaderAppBars( ) BottomReaderBar( + backgroundColor = backgroundColor, readingMode = readingMode, onClickReadingMode = onClickReadingMode, orientationMode = orientationMode, 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 8f855a32f..a2a92d1e8 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 @@ -13,15 +13,10 @@ import android.graphics.Paint import android.net.Uri import android.os.Build import android.os.Bundle -import android.text.TextUtils import android.view.KeyEvent -import android.view.Menu -import android.view.MenuItem import android.view.MotionEvent import android.view.View.LAYER_TYPE_HARDWARE import android.view.WindowManager -import android.view.animation.Animation -import android.view.animation.AnimationUtils import android.widget.Toast import androidx.activity.viewModels import androidx.compose.foundation.layout.Arrangement @@ -44,8 +39,7 @@ import androidx.core.view.WindowInsetsControllerCompat import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView -import com.google.android.material.internal.ToolbarUtils -import com.google.android.material.shape.MaterialShapeDrawable +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 @@ -74,13 +68,11 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator import eu.kanade.tachiyomi.ui.webview.WebViewActivity -import eu.kanade.tachiyomi.util.system.applySystemAnimatorScale import eu.kanade.tachiyomi.util.system.hasDisplayCutout import eu.kanade.tachiyomi.util.system.isNightMode import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.view.setComposeContent -import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.filterNotNull @@ -265,47 +257,6 @@ class ReaderActivity : BaseActivity() { assistUrl?.let { outContent.webUri = it.toUri() } } - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.reader, menu) - - val isChapterBookmarked = viewModel.getCurrentChapter()?.chapter?.bookmark ?: false - menu.findItem(R.id.action_bookmark).isVisible = !isChapterBookmarked - menu.findItem(R.id.action_remove_bookmark).isVisible = isChapterBookmarked - - val isHttpSource = viewModel.getSource() is HttpSource - menu.findItem(R.id.action_open_in_web_view).isVisible = isHttpSource - menu.findItem(R.id.action_share).isVisible = isHttpSource - - return true - } - - /** - * Called when an item of the options menu was clicked. Used to handle clicks on our menu - * entries. - */ - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.action_open_in_web_view -> { - openChapterInWebView() - } - R.id.action_bookmark -> { - viewModel.bookmarkCurrentChapter(true) - invalidateOptionsMenu() - } - R.id.action_remove_bookmark -> { - viewModel.bookmarkCurrentChapter(false) - invalidateOptionsMenu() - } - R.id.action_share -> { - assistUrl?.let { - val intent = it.toUri().toShareIntent(this, type = "text/plain") - startActivity(Intent.createChooser(intent, getString(R.string.action_share))) - } - } - } - return super.onOptionsItemSelected(item) - } - /** * Called when the user clicks the back key or the button on the toolbar. The call is * delegated to the presenter. @@ -348,35 +299,12 @@ class ReaderActivity : BaseActivity() { * Initializes the reader menu. It sets up click listeners and the initial visibility. */ private fun initializeMenu() { - setSupportActionBar(binding.toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - binding.toolbar.setNavigationOnClickListener { - onBackPressedDispatcher.onBackPressed() - } - - binding.toolbar.applyInsetter { - type(navigationBars = true, statusBars = true) { - margin(top = true, horizontal = true) - } - } binding.dialogRoot.applyInsetter { type(navigationBars = true) { margin(vertical = true, horizontal = true) } } - binding.toolbar.setOnClickListener { - viewModel.manga?.id?.let { id -> - startActivity( - Intent(this, MainActivity::class.java).apply { - action = Constants.SHORTCUT_MANGA - putExtra(Constants.MANGA_EXTRA, id) - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - }, - ) - } - } - binding.pageNumber.setComposeContent { val state by viewModel.state.collectAsState() val showPageNumber by viewModel.readerPreferences.showPageNumber().collectAsState() @@ -400,6 +328,9 @@ class ReaderActivity : BaseActivity() { ) } + val isHttpSource = viewModel.getSource() is HttpSource + val isFullscreen by readerPreferences.fullscreen().collectAsState() + val cropBorderPaged by readerPreferences.cropBorders().collectAsState() val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() val isPagerType = ReadingModeType.isPagerType(viewModel.getMangaReadingMode()) @@ -407,8 +338,18 @@ class ReaderActivity : BaseActivity() { ReaderAppBars( visible = state.menuVisible, - viewer = state.viewer, + fullscreen = isFullscreen, + mangaTitle = state.manga?.title, + chapterTitle = state.currentChapter?.chapter?.name, + navigateUp = onBackPressedDispatcher::onBackPressed, + onClickTopAppBar = ::openMangaScreen, + bookmarked = state.bookmarked, + onToggleBookmarked = viewModel::toggleChapterBookmark, + onOpenInWebView = ::openChapterInWebView.takeIf { isHttpSource }, + onShare = ::shareChapter.takeIf { isHttpSource }, + + viewer = state.viewer, onNextChapter = ::loadNextChapter, enabledNext = state.viewerChapters?.nextChapter != null, onPreviousChapter = ::loadPreviousChapter, @@ -435,15 +376,8 @@ class ReaderActivity : BaseActivity() { cropEnabled = cropEnabled, onClickCropBorder = { val enabled = viewModel.toggleCropBorders() - menuToggleToast?.cancel() - menuToggleToast = toast( - if (enabled) { - R.string.on - } else { - R.string.off - }, - ) + menuToggleToast = toast(if (enabled) R.string.on else R.string.off) }, onClickSettings = viewModel::openSettingsDialog, ) @@ -507,13 +441,9 @@ class ReaderActivity : BaseActivity() { } } - val toolbarBackground = (binding.toolbar.background as MaterialShapeDrawable).apply { - elevation = resources.getDimension(R.dimen.m3_sys_elevation_level2) - alpha = if (isNightMode()) 230 else 242 // 90% dark 95% light - } val toolbarColor = ColorUtils.setAlphaComponent( - toolbarBackground.resolvedTintColor, - toolbarBackground.alpha, + SurfaceColors.SURFACE_2.getColor(this), + if (isNightMode()) 230 else 242, // 90% dark 95% light ) window.statusBarColor = toolbarColor if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { @@ -531,35 +461,12 @@ class ReaderActivity : BaseActivity() { viewModel.showMenus(visible) if (visible) { windowInsetsController.show(WindowInsetsCompat.Type.systemBars()) - binding.readerMenu.isVisible = true - - val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top) - toolbarAnimation.applySystemAnimatorScale(this) - toolbarAnimation.setAnimationListener( - object : SimpleAnimationListener() { - override fun onAnimationStart(animation: Animation) { - // Fix status bar being translucent the first time it's opened. - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) - } - }, - ) - binding.toolbar.startAnimation(toolbarAnimation) + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) } else { if (readerPreferences.fullscreen().get()) { windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE } - - val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_top) - toolbarAnimation.applySystemAnimatorScale(this) - toolbarAnimation.setAnimationListener( - object : SimpleAnimationListener() { - override fun onAnimationEnd(animation: Animation) { - binding.readerMenu.isVisible = false - } - }, - ) - binding.toolbar.startAnimation(toolbarAnimation) } } @@ -593,14 +500,24 @@ class ReaderActivity : BaseActivity() { showReadingModeToast(viewModel.getMangaReadingMode()) } - supportActionBar?.title = manga.title - loadingIndicator = ReaderProgressIndicator(this) binding.readerContainer.addView(loadingIndicator) startPostponedEnterTransition() } + private fun openMangaScreen() { + viewModel.manga?.id?.let { id -> + startActivity( + Intent(this, MainActivity::class.java).apply { + action = Constants.SHORTCUT_MANGA + putExtra(Constants.MANGA_EXTRA, id) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + }, + ) + } + } + private fun openChapterInWebView() { val manga = viewModel.manga ?: return val source = viewModel.getSource() ?: return @@ -610,6 +527,13 @@ class ReaderActivity : BaseActivity() { } } + private fun shareChapter() { + assistUrl?.let { + val intent = it.toUri().toShareIntent(this, type = "text/plain") + startActivity(Intent.createChooser(intent, getString(R.string.action_share))) + } + } + private fun showReadingModeToast(mode: Int) { try { readingModeToast?.cancel() @@ -629,15 +553,6 @@ class ReaderActivity : BaseActivity() { binding.readerContainer.removeView(loadingIndicator) viewModel.state.value.viewer?.setChapters(viewerChapters) - binding.toolbar.subtitle = viewerChapters.currChapter.chapter.name - ToolbarUtils.getSubtitleTextView(binding.toolbar)?.let { - it.ellipsize = TextUtils.TruncateAt.MARQUEE - it.isSelected = true - } - - // Invalidate menu to show proper chapter bookmark state - invalidateOptionsMenu() - lifecycleScope.launchIO { viewModel.getChapterUrl()?.let { url -> assistUrl = url @@ -675,7 +590,7 @@ class ReaderActivity : BaseActivity() { */ private fun moveToPageIndex(index: Int) { val viewer = viewModel.state.value.viewer ?: return - val currentChapter = viewModel.getCurrentChapter() ?: return + val currentChapter = viewModel.state.value.currentChapter ?: return val page = currentChapter.pages?.getOrNull(index) ?: return viewer.moveToPage(page) } 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 55be5fd61..c16c5a362 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 @@ -298,7 +298,10 @@ class ReaderViewModel @JvmOverloads constructor( it.viewerChapters?.unref() chapterToDownload = cancelQueuedDownloads(newChapters.currChapter) - it.copy(viewerChapters = newChapters) + it.copy( + viewerChapters = newChapters, + bookmarked = newChapters.currChapter.chapter.bookmark, + ) } } return newChapters @@ -567,8 +570,8 @@ class ReaderViewModel @JvmOverloads constructor( /** * Returns the currently active chapter. */ - fun getCurrentChapter(): ReaderChapter? { - return state.value.viewerChapters?.currChapter + private fun getCurrentChapter(): ReaderChapter? { + return state.value.currentChapter } fun getSource() = manga?.source?.let { sourceManager.getOrStub(it) } as? HttpSource @@ -588,9 +591,11 @@ class ReaderViewModel @JvmOverloads constructor( /** * Bookmarks the currently active chapter. */ - fun bookmarkCurrentChapter(bookmarked: Boolean) { + fun toggleChapterBookmark() { val chapter = getCurrentChapter()?.chapter ?: return - chapter.bookmark = bookmarked // Otherwise the bookmark icon doesn't update + val bookmarked = !chapter.bookmark + chapter.bookmark = bookmarked + viewModelScope.launchNonCancellable { updateChapter.await( ChapterUpdate( @@ -599,6 +604,12 @@ class ReaderViewModel @JvmOverloads constructor( ), ) } + + mutableState.update { + it.copy( + bookmarked = bookmarked, + ) + } } /** @@ -873,6 +884,7 @@ class ReaderViewModel @JvmOverloads constructor( data class State( val manga: Manga? = null, val viewerChapters: ViewerChapters? = null, + val bookmarked: Boolean = false, val isLoadingAdjacentChapter: Boolean = false, val currentPage: Int = -1, @@ -883,8 +895,11 @@ class ReaderViewModel @JvmOverloads constructor( val dialog: Dialog? = null, val menuVisible: Boolean = false, ) { + val currentChapter: ReaderChapter? + get() = viewerChapters?.currChapter + val totalPages: Int - get() = viewerChapters?.currChapter?.pages?.size ?: -1 + get() = currentChapter?.pages?.size ?: -1 } sealed interface Dialog { diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/listener/SimpleAnimationListener.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/listener/SimpleAnimationListener.kt deleted file mode 100644 index d06ef6443..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/listener/SimpleAnimationListener.kt +++ /dev/null @@ -1,11 +0,0 @@ -package eu.kanade.tachiyomi.widget.listener - -import android.view.animation.Animation - -open class SimpleAnimationListener : Animation.AnimationListener { - override fun onAnimationRepeat(animation: Animation) {} - - override fun onAnimationEnd(animation: Animation) {} - - override fun onAnimationStart(animation: Animation) {} -} diff --git a/app/src/main/res/anim/enter_from_top.xml b/app/src/main/res/anim/enter_from_top.xml deleted file mode 100644 index ec0431ba0..000000000 --- a/app/src/main/res/anim/enter_from_top.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/anim/exit_to_top.xml b/app/src/main/res/anim/exit_to_top.xml deleted file mode 100644 index 3a6f3e9db..000000000 --- a/app/src/main/res/anim/exit_to_top.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bookmark_24dp.xml b/app/src/main/res/drawable/ic_bookmark_24dp.xml deleted file mode 100644 index 0c63a2e54..000000000 --- a/app/src/main/res/drawable/ic_bookmark_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_bookmark_border_24dp.xml b/app/src/main/res/drawable/ic_bookmark_border_24dp.xml deleted file mode 100644 index c3d2916eb..000000000 --- a/app/src/main/res/drawable/ic_bookmark_border_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/reader_activity.xml b/app/src/main/res/layout/reader_activity.xml index ac9b535b0..2401432ff 100644 --- a/app/src/main/res/layout/reader_activity.xml +++ b/app/src/main/res/layout/reader_activity.xml @@ -1,5 +1,4 @@ @@ -42,22 +41,6 @@ android:layout_height="match_parent" android:visibility="gone" /> - - - - - - - - - - - - - - - - - From 0be7ac5871a717e97195b7cfc1051fdbcced1e94 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 14 Oct 2023 22:22:46 -0400 Subject: [PATCH 12/37] Bump dependencies --- app/build.gradle.kts | 2 +- gradle/androidx.versions.toml | 4 +--- gradle/libs.versions.toml | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5f8b6166e..5f6cb6177 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -192,7 +192,7 @@ dependencies { implementation(androidx.bundles.lifecycle) // Job scheduling - implementation(androidx.bundles.workmanager) + implementation(androidx.workmanager) // RxJava implementation(libs.rxjava) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index f9db071ec..ad62d9611 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -21,8 +21,7 @@ lifecycle-common = { module = "androidx.lifecycle:lifecycle-common", version.ref lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "lifecycle_version" } lifecycle-runtimektx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle_version" } -work-runtime = "androidx.work:work-runtime-ktx:2.8.1" -guava = "com.google.guava:guava:32.1.2-android" +workmanager = "androidx.work:work-runtime-ktx:2.8.1" paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging_version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } @@ -34,4 +33,3 @@ test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0-alpha04" [bundles] lifecycle = ["lifecycle-common", "lifecycle-process", "lifecycle-runtimektx"] -workmanager = ["work-runtime", "guava"] diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2f37fce8b..ea5741eaa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version. voyager-tab-navigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" } voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" } -ktlint = "org.jlleitschuh.gradle:ktlint-gradle:11.6.0" +ktlint = "org.jlleitschuh.gradle:ktlint-gradle:11.6.1" [bundles] okhttp = ["okhttp-core", "okhttp-logging", "okhttp-dnsoverhttps"] From 447bcb28efa890ea1ebd73183b9ae25e8150be39 Mon Sep 17 00:00:00 2001 From: Caleb Morris Date: Sat, 14 Oct 2023 19:23:11 -0700 Subject: [PATCH 13/37] [dev QoL] Added AndroidStudio previews for [presentation.history] namespace (#10012) * Added display preview for HistoryDialogs * Added preview with provider for each branch for HistoryItem * Added previews for HistoryScreen Created in-memory preferences construct for when its needed at top-level injection * Fixed ktlint violations --- .../presentation/history/HistoryScreen.kt | 37 +++++- .../HistoryScreenModelStateProvider.kt | 109 ++++++++++++++++++ .../history/HistoryUiModelProviders.kt | 13 +++ .../history/components/HistoryDialogs.kt | 13 +++ .../history/components/HistoryItem.kt | 19 +++ .../HistoryWithRelationsProvider.kt | 62 ++++++++++ .../preference/InMemoryPreferenceStore.kt | 96 +++++++++++++++ 7 files changed, 348 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/eu/kanade/presentation/history/HistoryScreenModelStateProvider.kt create mode 100644 app/src/main/java/eu/kanade/presentation/history/HistoryUiModelProviders.kt create mode 100644 app/src/main/java/eu/kanade/presentation/history/components/HistoryWithRelationsProvider.kt create mode 100644 core/src/main/java/tachiyomi/core/preference/InMemoryPreferenceStore.kt 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 45dc67fdb..b2ffb6e5e 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.PreviewParameter import eu.kanade.domain.ui.UiPreferences import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBarActions @@ -18,13 +19,16 @@ import eu.kanade.presentation.components.AppBarTitle import eu.kanade.presentation.components.RelativeDateHeader import eu.kanade.presentation.components.SearchToolbar import eu.kanade.presentation.history.components.HistoryItem +import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.history.HistoryScreenModel +import tachiyomi.core.preference.InMemoryPreferenceStore import tachiyomi.domain.history.model.HistoryWithRelations 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 @@ -37,6 +41,7 @@ fun HistoryScreen( onClickCover: (mangaId: Long) -> Unit, onClickResume: (mangaId: Long, chapterId: Long) -> Unit, onDialogChange: (HistoryScreenModel.Dialog?) -> Unit, + preferences: UiPreferences = Injekt.get(), ) { Scaffold( topBar = { scrollBehavior -> @@ -82,6 +87,7 @@ fun HistoryScreen( onClickCover = { history -> onClickCover(history.mangaId) }, onClickResume = { history -> onClickResume(history.mangaId, history.chapterId) }, onClickDelete = { item -> onDialogChange(HistoryScreenModel.Dialog.Delete(item)) }, + preferences = preferences, ) } } @@ -95,7 +101,7 @@ private fun HistoryScreenContent( onClickCover: (HistoryWithRelations) -> Unit, onClickResume: (HistoryWithRelations) -> Unit, onClickDelete: (HistoryWithRelations) -> Unit, - preferences: UiPreferences = Injekt.get(), + preferences: UiPreferences, ) { val relativeTime = remember { preferences.relativeTime().get() } val dateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat().get()) } @@ -141,3 +147,32 @@ sealed interface HistoryUiModel { data class Header(val date: Date) : HistoryUiModel data class Item(val item: HistoryWithRelations) : HistoryUiModel } + +@ThemePreviews +@Composable +internal fun HistoryScreenPreviews( + @PreviewParameter(HistoryScreenModelStateProvider::class) + historyState: HistoryScreenModel.State, +) { + TachiyomiTheme { + HistoryScreen( + state = historyState, + snackbarHostState = SnackbarHostState(), + onSearchQueryChange = {}, + onClickCover = {}, + onClickResume = { _, _ -> run {} }, + onDialogChange = {}, + preferences = UiPreferences( + InMemoryPreferenceStore( + sequenceOf( + InMemoryPreferenceStore.InMemoryPreference( + key = "relative_time_v2", + data = false, + defaultValue = false, + ), + ), + ), + ), + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/history/HistoryScreenModelStateProvider.kt b/app/src/main/java/eu/kanade/presentation/history/HistoryScreenModelStateProvider.kt new file mode 100644 index 000000000..2c07b81e0 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/history/HistoryScreenModelStateProvider.kt @@ -0,0 +1,109 @@ +package eu.kanade.presentation.history + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import eu.kanade.tachiyomi.ui.history.HistoryScreenModel +import tachiyomi.domain.history.model.HistoryWithRelations +import tachiyomi.domain.manga.model.MangaCover +import java.time.Instant +import java.time.temporal.ChronoUnit +import java.util.Date +import kotlin.random.Random + +class HistoryScreenModelStateProvider : PreviewParameterProvider { + + private val multiPage = HistoryScreenModel.State( + searchQuery = null, + list = + listOf(HistoryUiModelExamples.headerToday) + .asSequence() + .plus(HistoryUiModelExamples.items().take(3)) + .plus(HistoryUiModelExamples.header { it.minus(1, ChronoUnit.DAYS) }) + .plus(HistoryUiModelExamples.items().take(1)) + .plus(HistoryUiModelExamples.header { it.minus(2, ChronoUnit.DAYS) }) + .plus(HistoryUiModelExamples.items().take(7)) + .toList(), + dialog = null, + ) + + private val shortRecent = HistoryScreenModel.State( + searchQuery = null, + list = listOf( + HistoryUiModelExamples.headerToday, + HistoryUiModelExamples.items().first(), + ), + dialog = null, + ) + + private val shortFuture = HistoryScreenModel.State( + searchQuery = null, + list = listOf( + HistoryUiModelExamples.headerTomorrow, + HistoryUiModelExamples.items().first(), + ), + dialog = null, + ) + + private val empty = HistoryScreenModel.State( + searchQuery = null, + list = listOf(), + dialog = null, + ) + + private val loadingWithSearchQuery = HistoryScreenModel.State( + searchQuery = "Example Search Query", + ) + + private val loading = HistoryScreenModel.State( + searchQuery = null, + list = null, + dialog = null, + ) + + override val values: Sequence = sequenceOf( + multiPage, + shortRecent, + shortFuture, + empty, + loadingWithSearchQuery, + loading, + ) + + private object HistoryUiModelExamples { + val headerToday = header() + val headerTomorrow = + HistoryUiModel.Header(Date.from(Instant.now().plus(1, ChronoUnit.DAYS))) + + fun header(instantBuilder: (Instant) -> Instant = { it }) = + HistoryUiModel.Header(Date.from(instantBuilder(Instant.now()))) + + fun items() = sequence { + var count = 1 + while (true) { + yield(randItem { it.copy(title = "Example Title $count") }) + count += 1 + } + } + + fun randItem(historyBuilder: (HistoryWithRelations) -> HistoryWithRelations = { it }) = + HistoryUiModel.Item( + historyBuilder( + HistoryWithRelations( + id = Random.nextLong(), + chapterId = Random.nextLong(), + mangaId = Random.nextLong(), + title = "Test Title", + chapterNumber = Random.nextDouble(), + readAt = Date.from(Instant.now()), + readDuration = Random.nextLong(), + coverData = MangaCover( + mangaId = Random.nextLong(), + sourceId = Random.nextLong(), + isMangaFavorite = Random.nextBoolean(), + url = "https://example.com/cover.png", + lastModified = Random.nextLong(), + ), + ), + ), + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/history/HistoryUiModelProviders.kt b/app/src/main/java/eu/kanade/presentation/history/HistoryUiModelProviders.kt new file mode 100644 index 000000000..16200635f --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/history/HistoryUiModelProviders.kt @@ -0,0 +1,13 @@ +package eu.kanade.presentation.history + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import java.time.Instant +import java.util.Date + +object HistoryUiModelProviders { + + class HeadNow : PreviewParameterProvider { + override val values: Sequence = + sequenceOf(HistoryUiModel.Header(Date.from(Instant.now()))) + } +} 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 12db68602..f76a1fa5c 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 @@ -18,7 +18,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R +import tachiyomi.presentation.core.util.ThemePreviews @Composable fun HistoryDeleteDialog( @@ -101,3 +103,14 @@ fun HistoryDeleteAllDialog( }, ) } + +@ThemePreviews +@Composable +internal fun HistoryDeleteDialogPreview() { + TachiyomiTheme { + HistoryDeleteDialog( + onDismissRequest = {}, + onDelete = { _ -> run {} }, + ) + } +} 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 08ce2635b..6b1bb1e0e 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 @@ -19,13 +19,16 @@ 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.PreviewParameter import androidx.compose.ui.unit.dp import eu.kanade.presentation.manga.components.MangaCover +import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.presentation.util.formatChapterNumber 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 HISTORY_ITEM_HEIGHT = 96.dp @@ -87,3 +90,19 @@ fun HistoryItem( } } } + +@ThemePreviews +@Composable +internal fun HistoryItemPreviews( + @PreviewParameter(HistoryWithRelationsProvider::class) + historyWithRelations: HistoryWithRelations, +) { + TachiyomiTheme { + HistoryItem( + history = historyWithRelations, + onClickCover = {}, + onClickResume = {}, + onClickDelete = {}, + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/history/components/HistoryWithRelationsProvider.kt b/app/src/main/java/eu/kanade/presentation/history/components/HistoryWithRelationsProvider.kt new file mode 100644 index 000000000..78347ed36 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/history/components/HistoryWithRelationsProvider.kt @@ -0,0 +1,62 @@ +package eu.kanade.presentation.history.components + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import tachiyomi.domain.history.model.HistoryWithRelations +import java.util.Date + +internal class HistoryWithRelationsProvider : PreviewParameterProvider { + + private val simple = HistoryWithRelations( + id = 1L, + chapterId = 2L, + mangaId = 3L, + title = "Test Title", + chapterNumber = 10.2, + readAt = Date(1697247357L), + readDuration = 123L, + coverData = tachiyomi.domain.manga.model.MangaCover( + mangaId = 3L, + sourceId = 4L, + isMangaFavorite = false, + url = "https://example.com/cover.png", + lastModified = 5L, + ), + ) + + private val historyWithoutReadAt = HistoryWithRelations( + id = 1L, + chapterId = 2L, + mangaId = 3L, + title = "Test Title", + chapterNumber = 10.2, + readAt = null, + readDuration = 123L, + coverData = tachiyomi.domain.manga.model.MangaCover( + mangaId = 3L, + sourceId = 4L, + isMangaFavorite = false, + url = "https://example.com/cover.png", + lastModified = 5L, + ), + ) + + private val historyWithNegativeChapterNumber = HistoryWithRelations( + id = 1L, + chapterId = 2L, + mangaId = 3L, + title = "Test Title", + chapterNumber = -2.0, + readAt = Date(1697247357L), + readDuration = 123L, + coverData = tachiyomi.domain.manga.model.MangaCover( + mangaId = 3L, + sourceId = 4L, + isMangaFavorite = false, + url = "https://example.com/cover.png", + lastModified = 5L, + ), + ) + + override val values: Sequence + get() = sequenceOf(simple, historyWithoutReadAt, historyWithNegativeChapterNumber) +} diff --git a/core/src/main/java/tachiyomi/core/preference/InMemoryPreferenceStore.kt b/core/src/main/java/tachiyomi/core/preference/InMemoryPreferenceStore.kt new file mode 100644 index 000000000..ad3937d91 --- /dev/null +++ b/core/src/main/java/tachiyomi/core/preference/InMemoryPreferenceStore.kt @@ -0,0 +1,96 @@ +package tachiyomi.core.preference + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.stateIn + +/** + * Local-copy implementation of PreferenceStore mostly for test and preview purposes + */ +class InMemoryPreferenceStore( + private val initialPreferences: Sequence> = sequenceOf(), +) : PreferenceStore { + + private val preferences: Map> = + initialPreferences.toList().associateBy { it.key() } + + override fun getString(key: String, defaultValue: String): Preference { + val default = InMemoryPreference(key, null, defaultValue) + val data: String? = preferences[key]?.get() as? String + return if (data == null) default else InMemoryPreference(key, data, defaultValue) + } + + override fun getLong(key: String, defaultValue: Long): Preference { + val default = InMemoryPreference(key, null, defaultValue) + val data: Long? = preferences[key]?.get() as? Long + return if (data == null) default else InMemoryPreference(key, data, defaultValue) + } + + override fun getInt(key: String, defaultValue: Int): Preference { + val default = InMemoryPreference(key, null, defaultValue) + val data: Int? = preferences[key]?.get() as? Int + return if (data == null) default else InMemoryPreference(key, data, defaultValue) + } + + override fun getFloat(key: String, defaultValue: Float): Preference { + val default = InMemoryPreference(key, null, defaultValue) + val data: Float? = preferences[key]?.get() as? Float + return if (data == null) default else InMemoryPreference(key, data, defaultValue) + } + + override fun getBoolean(key: String, defaultValue: Boolean): Preference { + val default = InMemoryPreference(key, null, defaultValue) + val data: Boolean? = preferences[key]?.get() as? Boolean + return if (data == null) default else InMemoryPreference(key, data, defaultValue) + } + + override fun getStringSet(key: String, defaultValue: Set): Preference> { + TODO("Not yet implemented") + } + + override fun getObject( + key: String, + defaultValue: T, + serializer: (T) -> String, + deserializer: (String) -> T, + ): Preference { + val default = InMemoryPreference(key, null, defaultValue) + val data: T? = preferences[key]?.get() as? T + return if (data == null) default else InMemoryPreference(key, data, defaultValue) + } + + override fun getAll(): Map { + return preferences + } + + class InMemoryPreference( + private val key: String, + private var data: T?, + private val defaultValue: T, + ) : Preference { + override fun key(): String = key + + override fun get(): T = data ?: defaultValue() + + override fun isSet(): Boolean = data != null + + override fun delete() { + data = null + } + + override fun defaultValue(): T = defaultValue + + override fun changes(): Flow = flow { data } + + override fun stateIn(scope: CoroutineScope): StateFlow { + return changes().stateIn(scope, SharingStarted.Eagerly, get()) + } + + override fun set(value: T) { + data = value + } + } +} From 82a9d36df7c8a22c7dbd7762ecc38dbdacd2626e Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 14 Oct 2023 22:46:51 -0400 Subject: [PATCH 14/37] Minor cleanup --- .github/renovate.json5 | 5 ----- app/.gitignore | 1 - app/shortcuts.xml | 1 - .../history/components/HistoryDialogs.kt | 4 ++-- .../history/components/HistoryItem.kt | 6 +++--- .../tachiyomi/ui/reader/ReaderActivity.kt | 20 +++++++------------ 6 files changed, 12 insertions(+), 25 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 55dae05ca..d333b80a6 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -5,11 +5,6 @@ ], "schedule": ["every sunday"], "packageRules": [ - { - "managers": ["maven"], - "packageNames": ["com.google.guava:guava"], - "versionScheme": "docker" - }, { // Compiler plugins are tightly coupled to Kotlin version "groupName": "Kotlin", diff --git a/app/.gitignore b/app/.gitignore index 88f41197e..12864471f 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1,4 +1,3 @@ /build *iml *.iml -custom.gradle diff --git a/app/shortcuts.xml b/app/shortcuts.xml index b9e38f27c..48936aafe 100644 --- a/app/shortcuts.xml +++ b/app/shortcuts.xml @@ -1,5 +1,4 @@ - run {} }, + onDelete = {}, ) } } 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 6b1bb1e0e..cd37192f6 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 @@ -30,7 +30,7 @@ import tachiyomi.domain.history.model.HistoryWithRelations import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.util.ThemePreviews -private val HISTORY_ITEM_HEIGHT = 96.dp +private val HistoryItemHeight = 96.dp @Composable fun HistoryItem( @@ -43,7 +43,7 @@ fun HistoryItem( Row( modifier = modifier .clickable(onClick = onClickResume) - .height(HISTORY_ITEM_HEIGHT) + .height(HistoryItemHeight) .padding(horizontal = MaterialTheme.padding.medium, vertical = MaterialTheme.padding.small), verticalAlignment = Alignment.CenterVertically, ) { @@ -93,7 +93,7 @@ fun HistoryItem( @ThemePreviews @Composable -internal fun HistoryItemPreviews( +private fun HistoryItemPreviews( @PreviewParameter(HistoryWithRelationsProvider::class) historyWithRelations: HistoryWithRelations, ) { 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 a2a92d1e8..6d58736e3 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 @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.ui.reader import android.annotation.SuppressLint -import android.annotation.TargetApi import android.app.assist.AssistContent import android.content.Context import android.content.Intent @@ -362,15 +361,11 @@ class ReaderActivity : BaseActivity() { }, readingMode = ReadingModeType.fromPreference( - viewModel.getMangaReadingMode( - resolveDefault = false, - ), + viewModel.getMangaReadingMode(resolveDefault = false), ), onClickReadingMode = viewModel::openReadingModeSelectDialog, orientationMode = OrientationType.fromPreference( - viewModel.getMangaOrientationType( - resolveDefault = false, - ), + viewModel.getMangaOrientationType(resolveDefault = false), ), onClickOrientationMode = viewModel::openOrientationModeSelectDialog, cropEnabled = cropEnabled, @@ -786,11 +781,9 @@ class ReaderActivity : BaseActivity() { .onEach(::setTrueColor) .launchIn(lifecycleScope) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - readerPreferences.cutoutShort().changes() - .onEach(::setCutoutShort) - .launchIn(lifecycleScope) - } + readerPreferences.cutoutShort().changes() + .onEach(::setCutoutShort) + .launchIn(lifecycleScope) readerPreferences.keepScreenOn().changes() .onEach(::setKeepScreenOn) @@ -842,8 +835,9 @@ class ReaderActivity : BaseActivity() { } } - @TargetApi(Build.VERSION_CODES.P) private fun setCutoutShort(enabled: Boolean) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return + window.attributes.layoutInDisplayCutoutMode = when (enabled) { true -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES false -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER From f79f0a7e97a6a754a5fbe621faeda6d0e62993f8 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 14 Oct 2023 22:47:02 -0400 Subject: [PATCH 15/37] Add haptics to SliderItem --- .../presentation/core/components/SettingsItems.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt index 08bf2d567..4f339dc49 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt @@ -40,6 +40,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import tachiyomi.core.preference.Preference @@ -160,6 +162,8 @@ fun SliderItem( valueText: String, onChange: (Int) -> Unit, ) { + val haptic = LocalHapticFeedback.current + Row( modifier = Modifier .fillMaxWidth() @@ -180,7 +184,13 @@ fun SliderItem( Slider( value = value.toFloat(), - onValueChange = { onChange(it.toInt()) }, + onValueChange = { + val newValue = it.toInt() + if (newValue != value) { + onChange(newValue) + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + } + }, modifier = Modifier.weight(1.5f), valueRange = min.toFloat()..max.toFloat(), steps = max - min, From 2bf77f1d814b411f8bd50bffcbca82b88064a2b0 Mon Sep 17 00:00:00 2001 From: Prasidh Gopal Anchan Date: Mon, 16 Oct 2023 02:40:01 +0530 Subject: [PATCH 16/37] Fix checkboxes not working after scrolling in filter sheet (#10023) Fixed an issue where CheckBox was not being checked after scrolling in the Filter tab --- .../presentation/core/components/AdaptiveSheet.kt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt index eea05b4ca..51fb672ee 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt @@ -167,7 +167,10 @@ fun AdaptiveSheet( .offset { IntOffset( 0, - anchoredDraggableState.offset.takeIf { it.isFinite() }?.roundToInt() ?: 0, + anchoredDraggableState.offset + .takeIf { it.isFinite() } + ?.roundToInt() + ?: 0, ) } .anchoredDraggable( @@ -238,8 +241,13 @@ private fun AnchoredDraggableState.preUpPostDownNestedScrollConnection() } override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - settle(velocity = available.toFloat()) - return available + val toFling = available.toFloat() + return if (toFling > 0) { + settle(toFling) + available + } else { + Velocity.Zero + } } private fun Float.toOffset(): Offset = Offset(0f, this) From ea99d77fda239c54d029223150f20cd69f9665c3 Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Mon, 16 Oct 2023 09:05:35 +0700 Subject: [PATCH 17/37] ExtensionLoader: Fix incorrect ext file deletion (#10026) Ref c492efcb31775a65464cf68b4a249bc5bb8e6016 --- .../java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt index 28161fcb3..c43af2fdc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt @@ -98,7 +98,7 @@ internal object ExtensionLoader { val target = File(getPrivateExtensionDir(context), "${extension.packageName}.$PRIVATE_EXTENSION_EXTENSION") return try { - file.delete() + target.delete() file.copyAndSetReadOnlyTo(target, overwrite = true) if (currentExtension != null) { ExtensionInstallReceiver.notifyReplaced(context, extension.packageName) From e572abb041cc0c410842fda1ed703f1b80a94d96 Mon Sep 17 00:00:00 2001 From: arkon Date: Tue, 17 Oct 2023 18:22:55 -0400 Subject: [PATCH 18/37] Show an error if backup file URI isn't returned to app when attempting restore Related to #10028 --- .../settings/screen/SettingsBackupScreen.kt | 35 ++++++++++--------- i18n/src/main/res/values/strings.xml | 1 + 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt index 5ab8f228a..3bd36f9b4 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt @@ -238,7 +238,7 @@ object SettingsBackupScreen : SearchableSettings { AlertDialog( onDismissRequest = onDismissRequest, title = { Text(text = stringResource(R.string.invalid_backup_file)) }, - text = { Text(text = "${err.uri}\n\n${err.message}") }, + text = { Text(text = listOfNotNull(err.uri, err.message).joinToString("\n\n")) }, dismissButton = { TextButton( onClick = { @@ -310,21 +310,24 @@ object SettingsBackupScreen : SearchableSettings { } }, ) { - if (it != null) { - val results = try { - BackupFileValidator().validate(context, it) - } catch (e: Exception) { - error = InvalidRestore(it, e.message.toString()) - return@rememberLauncherForActivityResult - } - - if (results.missingSources.isEmpty() && results.missingTrackers.isEmpty()) { - BackupRestoreJob.start(context, it) - return@rememberLauncherForActivityResult - } - - error = MissingRestoreComponents(it, results.missingSources, results.missingTrackers) + if (it == null) { + error = InvalidRestore(message = context.getString(R.string.file_null_uri_error)) + return@rememberLauncherForActivityResult } + + val results = try { + BackupFileValidator().validate(context, it) + } catch (e: Exception) { + error = InvalidRestore(it, e.message.toString()) + return@rememberLauncherForActivityResult + } + + if (results.missingSources.isEmpty() && results.missingTrackers.isEmpty()) { + BackupRestoreJob.start(context, it) + return@rememberLauncherForActivityResult + } + + error = MissingRestoreComponents(it, results.missingSources, results.missingTrackers) } return Preference.PreferenceItem.TextPreference( @@ -421,6 +424,6 @@ private data class MissingRestoreComponents( ) private data class InvalidRestore( - val uri: Uri, + val uri: Uri? = null, val message: String, ) diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index aca17a122..90eccfd8c 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -871,6 +871,7 @@ Select cover image Select backup file No file picker app found + File picker failed to return file to app Download From 22df12a680174890fe8f3559218b1819e37bf2f6 Mon Sep 17 00:00:00 2001 From: arkon Date: Tue, 17 Oct 2023 22:30:55 -0400 Subject: [PATCH 19/37] Change crash log info to just have actual WebView version --- .../more/settings/screen/debug/DebugInfoScreen.kt | 12 ++---------- .../java/eu/kanade/tachiyomi/util/CrashLogUtil.kt | 2 +- .../eu/kanade/tachiyomi/util/system/WebViewUtil.kt | 13 +++++++++++++ 3 files changed, 16 insertions(+), 11 deletions(-) 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 37fa0189d..0e3bcde93 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 @@ -1,7 +1,6 @@ package eu.kanade.presentation.more.settings.screen.debug import android.os.Build -import android.webkit.WebView import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.getValue @@ -16,6 +15,7 @@ import eu.kanade.presentation.more.settings.screen.about.AboutScreen import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.DeviceUtil +import eu.kanade.tachiyomi.util.system.WebViewUtil import kotlinx.coroutines.guava.await class DebugInfoScreen : Screen() { @@ -68,15 +68,7 @@ class DebugInfoScreen : Screen() { @Composable @ReadOnlyComposable private fun getWebViewVersion(): String { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val webView = WebView.getCurrentWebViewPackage() ?: return "how did you get here?" - val pm = LocalContext.current.packageManager - val label = webView.applicationInfo.loadLabel(pm) - val version = webView.versionName - return "$label $version" - } else { - return "Unknown" - } + return WebViewUtil.getVersion(LocalContext.current) } @Composable 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 c495c7008..505ec3cf9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt @@ -36,7 +36,7 @@ class CrashLogUtil(private val context: Context) { Device name: ${Build.DEVICE} Device model: ${Build.MODEL} Device product name: ${Build.PRODUCT} - WebView user agent: ${WebViewUtil.getInferredUserAgent(context)} + WebView: ${WebViewUtil.getVersion(context)} """.trimIndent() } } diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt index eb1ad9617..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 @@ -33,6 +34,18 @@ object WebViewUtil { .replace("Version/.* Chrome/".toRegex(), "Chrome/") } + 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" + } + } + fun supportsWebView(context: Context): Boolean { try { // May throw android.webkit.WebViewFactory$MissingWebViewPackageException if WebView From c4ce3dd46fe3ebf9b33b256106b8690e5543ddb8 Mon Sep 17 00:00:00 2001 From: arkon Date: Tue, 17 Oct 2023 22:32:13 -0400 Subject: [PATCH 20/37] Update background job preferences once settings are restored Co-authored-by: Jays2Kings --- .../java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt | 4 ++++ 1 file changed, 4 insertions(+) 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 c912be3f9..ec34ce08a 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 @@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.data.backup.models.IntPreferenceValue import eu.kanade.tachiyomi.data.backup.models.LongPreferenceValue import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue +import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.source.model.copyFrom import eu.kanade.tachiyomi.source.sourcePreferences import eu.kanade.tachiyomi.util.BackupUtil @@ -589,6 +590,9 @@ class BackupRestorer( private fun restoreAppPreferences(preferences: List) { restorePreferences(preferences, preferenceStore) + LibraryUpdateJob.setupTask(context) + BackupCreateJob.setupTask(context) + restoreProgress += 1 showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.app_settings), context.getString(R.string.restoring_backup)) } From 8f3681d79f1624a092e5c356c9459897f4220c29 Mon Sep 17 00:00:00 2001 From: Vlasov Roman Date: Thu, 19 Oct 2023 09:49:45 +0700 Subject: [PATCH 21/37] Change Shikimori domain from ".me" to ".one" (#10027) --- .../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 fd62f18fc..5df7fc941 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 @@ -194,7 +194,7 @@ class ShikimoriApi( 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 1302461518702b00af0cc920c389adef3cf1694a Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 18 Oct 2023 22:42:19 -0400 Subject: [PATCH 22/37] Bump dependencies --- gradle/androidx.versions.toml | 4 ++-- gradle/libs.versions.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index ad62d9611..98be1aa68 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -12,7 +12,7 @@ biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05" constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" corektx = "androidx.core:core-ktx:1.12.0" splashscreen = "androidx.core:core-splashscreen:1.0.1" -recyclerview = "androidx.recyclerview:recyclerview:1.3.1" +recyclerview = "androidx.recyclerview:recyclerview:1.3.2" viewpager = "androidx.viewpager:viewpager:1.1.0-alpha01" glance = "androidx.glance:glance-appwidget:1.0.0" profileinstaller = "androidx.profileinstaller:profileinstaller:1.3.1" @@ -26,7 +26,7 @@ workmanager = "androidx.work:work-runtime-ktx:2.8.1" paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging_version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } -benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-rc02" +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" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea5741eaa..7f3b34b54 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ aboutlib_version = "10.9.1" okhttp_version = "5.0.0-alpha.11" shizuku_version = "12.2.0" -sqlite = "2.3.1" +sqlite = "2.4.0" sqldelight = "2.0.0" leakcanary = "2.12" voyager = "1.0.0-rc07" @@ -64,7 +64,7 @@ swipe = "me.saket.swipe:swipe:1.2.0" logcat = "com.squareup.logcat:logcat:0.1" acra-http = "ch.acra:acra-http:5.11.2" -firebase-analytics = "com.google.firebase:firebase-analytics-ktx:21.3.0" +firebase-analytics = "com.google.firebase:firebase-analytics-ktx:21.4.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 8626a55fe4ee2fa5f61e6d4a2a8e0c7e3752cd25 Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 18 Oct 2023 22:50:09 -0400 Subject: [PATCH 23/37] Make text clickable when removing item from tracker --- .../tachiyomi/data/track/shikimori/ShikimoriApi.kt | 9 +++++---- .../tachiyomi/ui/manga/track/TrackInfoDialog.kt | 11 +++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) 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 5df7fc941..8e9033607 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 @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.data.track.shikimori +import android.net.Uri import androidx.core.net.toUri import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.model.TrackSearch @@ -37,12 +38,12 @@ class ShikimoriApi( private val authClient = client.newBuilder().addInterceptor(interceptor).build() - suspend fun addLibManga(track: Track, user_id: String): Track { + suspend fun addLibManga(track: Track, userId: String): Track { return withIOContext { with(json) { val payload = buildJsonObject { putJsonObject("user_rate") { - put("user_id", user_id) + put("user_id", userId) put("target_id", track.media_id) put("target_type", "Manga") put("chapters", track.last_chapter_read.toInt()) @@ -65,7 +66,7 @@ class ShikimoriApi( } } - suspend fun updateLibManga(track: Track, user_id: String): Track = addLibManga(track, user_id) + suspend fun updateLibManga(track: Track, userId: String): Track = addLibManga(track, userId) suspend fun deleteLibManga(track: Track): Track { return withIOContext { @@ -201,7 +202,7 @@ class ShikimoriApi( private const val redirectUrl = "tachiyomi://shikimori-auth" - fun authUrl() = loginUrl.toUri().buildUpon() + fun authUrl(): Uri = loginUrl.toUri().buildUpon() .appendQueryParameter("client_id", clientId) .appendQueryParameter("redirect_uri", redirectUrl) .appendQueryParameter("response_type", "code") diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index 6c811b7ad..1eb97b760 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.manga.track import android.app.Application import android.content.Context +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -759,8 +760,14 @@ private data class TrackerRemoveScreen( text = stringResource(R.string.track_delete_text, serviceName), ) if (sm.isDeletable()) { - Row(verticalAlignment = Alignment.CenterVertically) { - Checkbox(checked = removeRemoteTrack, onCheckedChange = { removeRemoteTrack = it }) + val onChange = { removeRemoteTrack = !removeRemoteTrack } + Row( + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = onChange), + verticalAlignment = Alignment.CenterVertically, + ) { + Checkbox(checked = removeRemoteTrack, onCheckedChange = { onChange() }) Text(text = stringResource(R.string.track_delete_remote_text, serviceName)) } } From c53172265b4dfba380a096c8d9107358515bf0e1 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 21 Oct 2023 09:42:12 -0400 Subject: [PATCH 24/37] Consistent labeled checkbox composable --- .../history/components/HistoryDialogs.kt | 39 +++----- .../library/DeleteLibraryMangaDialog.kt | 40 +++----- .../manga/ChapterSettingsDialog.kt | 26 ++--- .../settings/screen/SettingsBackupScreen.kt | 53 +++-------- .../widget/MultiSelectListPreferenceWidget.kt | 50 +++------- .../browse/migration/search/MigrateDialog.kt | 21 ++--- .../ui/manga/track/TrackInfoDialog.kt | 94 +++++++++---------- .../core/components/LabeledCheckbox.kt | 44 +++++++++ 8 files changed, 151 insertions(+), 216 deletions(-) create mode 100644 presentation-core/src/main/java/tachiyomi/presentation/core/components/LabeledCheckbox.kt 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 40d3ecfa7..0ceab8f61 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 @@ -1,12 +1,8 @@ package eu.kanade.presentation.history.components -import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.selection.toggleable import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Checkbox import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -14,12 +10,11 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember 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 import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R +import tachiyomi.presentation.core.components.LabeledCheckbox import tachiyomi.presentation.core.util.ThemePreviews @Composable @@ -34,28 +29,16 @@ fun HistoryDeleteDialog( Text(text = stringResource(R.string.action_remove)) }, text = { - Column { + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { Text(text = stringResource(R.string.dialog_with_checkbox_remove_description)) - Row( - modifier = Modifier - .padding(top = 16.dp) - .toggleable( - interactionSource = remember { MutableInteractionSource() }, - indication = null, - value = removeEverything, - onValueChange = { removeEverything = it }, - ), - verticalAlignment = Alignment.CenterVertically, - ) { - Checkbox( - checked = removeEverything, - onCheckedChange = null, - ) - Text( - modifier = Modifier.padding(start = 4.dp), - text = stringResource(R.string.dialog_with_checkbox_reset), - ) - } + + LabeledCheckbox( + label = stringResource(R.string.dialog_with_checkbox_reset), + checked = removeEverything, + onCheckedChange = { removeEverything = it }, + ) } }, onDismissRequest = onDismissRequest, diff --git a/app/src/main/java/eu/kanade/presentation/library/DeleteLibraryMangaDialog.kt b/app/src/main/java/eu/kanade/presentation/library/DeleteLibraryMangaDialog.kt index 1f6317a97..49a9a8360 100644 --- a/app/src/main/java/eu/kanade/presentation/library/DeleteLibraryMangaDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/DeleteLibraryMangaDialog.kt @@ -1,11 +1,7 @@ package eu.kanade.presentation.library -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Checkbox import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -13,11 +9,10 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import eu.kanade.tachiyomi.R import tachiyomi.core.preference.CheckboxState +import tachiyomi.presentation.core.components.LabeledCheckbox @Composable fun DeleteLibraryMangaDialog( @@ -62,27 +57,18 @@ fun DeleteLibraryMangaDialog( text = { Column { list.forEach { state -> - val onCheck = { - val index = list.indexOf(state) - if (index != -1) { - val mutableList = list.toMutableList() - mutableList[index] = state.next() as CheckboxState.State - list = mutableList.toList() - } - } - - Row( - modifier = Modifier - .fillMaxWidth() - .clickable { onCheck() }, - verticalAlignment = Alignment.CenterVertically, - ) { - Checkbox( - checked = state.isChecked, - onCheckedChange = { onCheck() }, - ) - Text(text = stringResource(state.value)) - } + LabeledCheckbox( + label = stringResource(state.value), + checked = state.isChecked, + onCheckedChange = { + val index = list.indexOf(state) + if (index != -1) { + val mutableList = list.toMutableList() + mutableList[index] = state.next() as CheckboxState.State + list = mutableList.toList() + } + }, + ) } } }, 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 7cfcbf053..9f842fead 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt @@ -1,16 +1,12 @@ 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.material3.AlertDialog -import androidx.compose.material3.Checkbox import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -19,7 +15,6 @@ 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 @@ -30,6 +25,7 @@ import eu.kanade.presentation.components.TabbedDialogPaddings import eu.kanade.tachiyomi.R import tachiyomi.core.preference.TriState import tachiyomi.domain.manga.model.Manga +import tachiyomi.presentation.core.components.LabeledCheckbox import tachiyomi.presentation.core.components.RadioItem import tachiyomi.presentation.core.components.SortItem import tachiyomi.presentation.core.components.TriStateItem @@ -172,6 +168,7 @@ private fun SetAsDefaultDialog( onConfirmed: (optionalChecked: Boolean) -> Unit, ) { var optionalChecked by rememberSaveable { mutableStateOf(false) } + AlertDialog( onDismissRequest = onDismissRequest, title = { Text(text = stringResource(R.string.chapter_settings)) }, @@ -181,20 +178,11 @@ private fun SetAsDefaultDialog( ) { Text(text = stringResource(R.string.confirm_set_chapter_settings)) - Row( - modifier = Modifier - .clickable { optionalChecked = !optionalChecked } - .padding(vertical = 8.dp) - .fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(12.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Checkbox( - checked = optionalChecked, - onCheckedChange = null, - ) - Text(text = stringResource(R.string.also_set_chapter_settings_for_library)) - } + LabeledCheckbox( + label = stringResource(R.string.also_set_chapter_settings_for_library), + checked = optionalChecked, + onCheckedChange = { optionalChecked = it }, + ) } }, dismissButton = { diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt index 3bd36f9b4..e35acffe0 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt @@ -8,20 +8,13 @@ import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.StringRes -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.heightIn -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.Checkbox import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -38,7 +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.compose.ui.unit.dp import androidx.core.net.toUri import com.hippo.unifile.UniFile import eu.kanade.presentation.extensions.RequestStoragePermission @@ -55,6 +47,7 @@ import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.toast import kotlinx.coroutines.launch import tachiyomi.domain.backup.service.BackupPreferences +import tachiyomi.presentation.core.components.LabeledCheckbox import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.util.collectAsState import tachiyomi.presentation.core.util.isScrolledToEnd @@ -160,22 +153,23 @@ object SettingsBackupScreen : SearchableSettings { val state = rememberLazyListState() ScrollbarLazyColumn(state = state) { item { - CreateBackupDialogItem( - isSelected = true, - title = stringResource(R.string.manga), + LabeledCheckbox( + label = stringResource(R.string.manga), + checked = true, + onCheckedChange = {}, ) } choices.forEach { (k, v) -> item { val isSelected = flags.contains(k) - CreateBackupDialogItem( - isSelected = isSelected, - title = stringResource(v), - modifier = Modifier.clickable { - if (isSelected) { - flags.remove(k) - } else { + LabeledCheckbox( + label = stringResource(v), + checked = isSelected, + onCheckedChange = { + if (it) { flags.add(k) + } else { + flags.remove(k) } }, ) @@ -204,29 +198,6 @@ object SettingsBackupScreen : SearchableSettings { ) } - @Composable - private fun CreateBackupDialogItem( - modifier: Modifier = Modifier, - isSelected: Boolean, - title: String, - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = modifier.fillMaxWidth(), - ) { - Checkbox( - modifier = Modifier.heightIn(min = 48.dp), - checked = isSelected, - onCheckedChange = null, - ) - Text( - text = title, - style = MaterialTheme.typography.bodyMedium.merge(), - modifier = Modifier.padding(start = 24.dp), - ) - } - } - @Composable private fun getRestoreBackupPref(): Preference.PreferenceItem.TextPreference { val context = LocalContext.current diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/MultiSelectListPreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/MultiSelectListPreferenceWidget.kt index 74ed60e01..3059be939 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/MultiSelectListPreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/MultiSelectListPreferenceWidget.kt @@ -1,30 +1,20 @@ package eu.kanade.presentation.more.settings.widget -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.selection.selectable import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Checkbox -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf 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.presentation.more.settings.Preference import eu.kanade.tachiyomi.R +import tachiyomi.presentation.core.components.LabeledCheckbox @Composable fun MultiSelectListPreferenceWidget( @@ -55,33 +45,17 @@ fun MultiSelectListPreferenceWidget( preference.entries.forEach { current -> item { val isSelected = selected.contains(current.key) - val onSelectionChanged = { - when (!isSelected) { - true -> selected.add(current.key) - false -> selected.remove(current.key) - } - } - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .clip(MaterialTheme.shapes.small) - .selectable( - selected = isSelected, - onClick = { onSelectionChanged() }, - ) - .minimumInteractiveComponentSize() - .fillMaxWidth(), - ) { - Checkbox( - checked = isSelected, - onCheckedChange = null, - ) - Text( - text = current.value, - style = MaterialTheme.typography.bodyMedium, - modifier = Modifier.padding(start = 24.dp), - ) - } + LabeledCheckbox( + label = current.value, + checked = isSelected, + onCheckedChange = { + if (it) { + selected.add(current.key) + } else { + selected.remove(current.key) + } + }, + ) } } } 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 ac8964412..386e8dd80 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 @@ -1,17 +1,13 @@ package eu.kanade.tachiyomi.ui.browse.migration.search import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column 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.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Checkbox import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -22,7 +18,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope 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 @@ -55,6 +50,7 @@ import tachiyomi.domain.manga.model.MangaUpdate import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.InsertTrack +import tachiyomi.presentation.core.components.LabeledCheckbox import tachiyomi.presentation.core.screens.LoadingScreen import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -92,16 +88,11 @@ internal fun MigrateDialog( modifier = Modifier.verticalScroll(rememberScrollState()), ) { flags.forEachIndexed { index, flag -> - val onChange = { selectedFlags[index] = !selectedFlags[index] } - Row( - modifier = Modifier - .fillMaxWidth() - .clickable(onClick = onChange), - verticalAlignment = Alignment.CenterVertically, - ) { - Checkbox(checked = selectedFlags[index], onCheckedChange = { onChange() }) - Text(text = context.getString(flag.titleId)) - } + LabeledCheckbox( + label = stringResource(flag.titleId), + checked = selectedFlags[index], + onCheckedChange = { selectedFlags[index] = it }, + ) } } }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index 1eb97b760..94e6bbe84 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.manga.track import android.app.Application import android.content.Context -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -13,7 +12,6 @@ import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Checkbox import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -33,6 +31,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.coroutineScope @@ -75,6 +74,7 @@ import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.track.interactor.DeleteTrack import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.model.Track +import tachiyomi.presentation.core.components.LabeledCheckbox import tachiyomi.presentation.core.components.material.AlertDialogContent import tachiyomi.presentation.core.components.material.padding import uy.kohesive.injekt.Injekt @@ -94,10 +94,10 @@ data class TrackInfoDialogHomeScreen( override fun Content() { val navigator = LocalNavigator.currentOrThrow val context = LocalContext.current - val sm = rememberScreenModel { Model(mangaId, sourceId) } + val screenModel = rememberScreenModel { Model(mangaId, sourceId) } val dateFormat = remember { UiPreferences.dateFormat(Injekt.get().dateFormat().get()) } - val state by sm.state.collectAsState() + val state by screenModel.state.collectAsState() TrackInfoDialogHome( trackItems = state.trackItems, @@ -146,7 +146,7 @@ data class TrackInfoDialogHomeScreen( }, onNewSearch = { if (it.tracker is EnhancedTracker) { - sm.registerEnhancedTracking(it) + screenModel.registerEnhancedTracking(it) } else { navigator.push( TrackerSearchScreen( @@ -261,19 +261,19 @@ private data class TrackStatusSelectorScreen( @Composable override fun Content() { val navigator = LocalNavigator.currentOrThrow - val sm = rememberScreenModel { + val screenModel = rememberScreenModel { Model( track = track, tracker = Injekt.get().get(serviceId)!!, ) } - val state by sm.state.collectAsState() + val state by screenModel.state.collectAsState() TrackStatusSelector( selection = state.selection, - onSelectionChange = sm::setSelection, - selections = remember { sm.getSelections() }, + onSelectionChange = screenModel::setSelection, + selections = remember { screenModel.getSelections() }, onConfirm = { - sm.setStatus() + screenModel.setStatus() navigator.pop() }, onDismissRequest = navigator::pop, @@ -314,20 +314,20 @@ private data class TrackChapterSelectorScreen( @Composable override fun Content() { val navigator = LocalNavigator.currentOrThrow - val sm = rememberScreenModel { + val screenModel = rememberScreenModel { Model( track = track, tracker = Injekt.get().get(serviceId)!!, ) } - val state by sm.state.collectAsState() + val state by screenModel.state.collectAsState() TrackChapterSelector( selection = state.selection, - onSelectionChange = sm::setSelection, - range = remember { sm.getRange() }, + onSelectionChange = screenModel::setSelection, + range = remember { screenModel.getRange() }, onConfirm = { - sm.setChapter() + screenModel.setChapter() navigator.pop() }, onDismissRequest = navigator::pop, @@ -373,20 +373,20 @@ private data class TrackScoreSelectorScreen( @Composable override fun Content() { val navigator = LocalNavigator.currentOrThrow - val sm = rememberScreenModel { + val screenModel = rememberScreenModel { Model( track = track, tracker = Injekt.get().get(serviceId)!!, ) } - val state by sm.state.collectAsState() + val state by screenModel.state.collectAsState() TrackScoreSelector( selection = state.selection, - onSelectionChange = sm::setSelection, - selections = remember { sm.getSelections() }, + onSelectionChange = screenModel::setSelection, + selections = remember { screenModel.getSelections() }, onConfirm = { - sm.setScore() + screenModel.setScore() navigator.pop() }, onDismissRequest = navigator::pop, @@ -484,7 +484,7 @@ private data class TrackDateSelectorScreen( @Composable override fun Content() { val navigator = LocalNavigator.currentOrThrow - val sm = rememberScreenModel { + val screenModel = rememberScreenModel { Model( track = track, tracker = Injekt.get().get(serviceId)!!, @@ -503,13 +503,13 @@ private data class TrackDateSelectorScreen( } else { stringResource(R.string.track_finished_reading_date) }, - initialSelectedDateMillis = sm.initialSelection, + initialSelectedDateMillis = screenModel.initialSelection, selectableDates = selectableDates, onConfirm = { - sm.setDate(it) + screenModel.setDate(it) navigator.pop() }, - onRemove = { sm.confirmRemoveDate(navigator) }.takeIf { canRemove }, + onRemove = { screenModel.confirmRemoveDate(navigator) }.takeIf { canRemove }, onDismissRequest = navigator::pop, ) } @@ -557,7 +557,7 @@ private data class TrackDateRemoverScreen( @Composable override fun Content() { val navigator = LocalNavigator.currentOrThrow - val sm = rememberScreenModel { + val screenModel = rememberScreenModel { Model( track = track, tracker = Injekt.get().get(serviceId)!!, @@ -579,7 +579,7 @@ private data class TrackDateRemoverScreen( ) }, text = { - val serviceName = sm.getServiceName() + val serviceName = screenModel.getServiceName() Text( text = if (start) { stringResource(R.string.track_remove_start_date_conf_text, serviceName) @@ -598,7 +598,7 @@ private data class TrackDateRemoverScreen( } FilledTonalButton( onClick = { - sm.removeDate() + screenModel.removeDate() navigator.popUntil { it is TrackInfoDialogHomeScreen } }, colors = ButtonDefaults.filledTonalButtonColors( @@ -643,7 +643,7 @@ data class TrackerSearchScreen( @Composable override fun Content() { val navigator = LocalNavigator.currentOrThrow - val sm = rememberScreenModel { + val screenModel = rememberScreenModel { Model( mangaId = mangaId, currentUrl = currentUrl, @@ -652,18 +652,18 @@ data class TrackerSearchScreen( ) } - val state by sm.state.collectAsState() + val state by screenModel.state.collectAsState() var textFieldValue by remember { mutableStateOf(TextFieldValue(initialQuery)) } TrackerSearch( query = textFieldValue, onQueryChange = { textFieldValue = it }, - onDispatchQuery = { sm.trackingSearch(textFieldValue.text) }, + onDispatchQuery = { screenModel.trackingSearch(textFieldValue.text) }, queryResult = state.queryResult, selected = state.selected, - onSelectedChange = sm::updateSelection, + onSelectedChange = screenModel::updateSelection, onConfirmSelection = { - sm.registerTracking(state.selected!!) + screenModel.registerTracking(state.selected!!) navigator.pop() }, onDismissRequest = navigator::pop, @@ -731,14 +731,14 @@ private data class TrackerRemoveScreen( @Composable override fun Content() { val navigator = LocalNavigator.currentOrThrow - val sm = rememberScreenModel { + val screenModel = rememberScreenModel { Model( mangaId = mangaId, track = track, tracker = Injekt.get().get(serviceId)!!, ) } - val serviceName = sm.getName() + val serviceName = screenModel.getName() var removeRemoteTrack by remember { mutableStateOf(false) } AlertDialogContent( modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars), @@ -755,21 +755,19 @@ private data class TrackerRemoveScreen( ) }, text = { - Column { + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { Text( text = stringResource(R.string.track_delete_text, serviceName), ) - if (sm.isDeletable()) { - val onChange = { removeRemoteTrack = !removeRemoteTrack } - Row( - modifier = Modifier - .fillMaxWidth() - .clickable(onClick = onChange), - verticalAlignment = Alignment.CenterVertically, - ) { - Checkbox(checked = removeRemoteTrack, onCheckedChange = { onChange() }) - Text(text = stringResource(R.string.track_delete_remote_text, serviceName)) - } + + if (screenModel.isDeletable()) { + LabeledCheckbox( + label = stringResource(R.string.track_delete_remote_text, serviceName), + checked = removeRemoteTrack, + onCheckedChange = { removeRemoteTrack = it }, + ) } } }, @@ -786,8 +784,8 @@ private data class TrackerRemoveScreen( } FilledTonalButton( onClick = { - sm.unregisterTracking(serviceId) - if (removeRemoteTrack) sm.deleteMangaFromService() + screenModel.unregisterTracking(serviceId) + if (removeRemoteTrack) screenModel.deleteMangaFromService() navigator.pop() }, colors = ButtonDefaults.filledTonalButtonColors( 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 new file mode 100644 index 000000000..0a72e4b0b --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/LabeledCheckbox.kt @@ -0,0 +1,44 @@ +package tachiyomi.presentation.core.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.material3.Checkbox +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.dp + +@Composable +fun LabeledCheckbox( + modifier: Modifier = Modifier, + label: String, + checked: Boolean, + onCheckedChange: (Boolean) -> Unit, +) { + Row( + modifier = modifier + .clip(MaterialTheme.shapes.small) + .fillMaxWidth() + .heightIn(min = 48.dp) + .clickable( + role = Role.Checkbox, + onClick = { onCheckedChange(!checked) }, + ), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + Checkbox( + checked = checked, + onCheckedChange = null, + ) + + Text(text = label) + } +} From e1b3345b9414e918d7bb2e99ecc47c77d2bcef79 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sat, 21 Oct 2023 15:44:05 +0200 Subject: [PATCH 25/37] Translations update from Hosted Weblate (#9992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Weblate translations Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ar/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cs/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/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/it/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ja/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nb_NO/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ne/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pl/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/th/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/vi/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/ Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/ Translation: Tachiyomi/Tachiyomi 0.x Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> Co-authored-by: Ali Aljishi Co-authored-by: C201 Co-authored-by: Dexroneum Co-authored-by: Diego D Co-authored-by: Eduard Ereza Martínez Co-authored-by: Esttven Co-authored-by: FateXBlood Co-authored-by: Giorgio Sanna Co-authored-by: ID-86 Co-authored-by: InfinityDouki56 Co-authored-by: ItsPoofy Co-authored-by: Jendrej Co-authored-by: Lyfja Co-authored-by: Lzmxya Co-authored-by: Maristella Kalil Victoriano Silva Co-authored-by: Milo Ivir Co-authored-by: Pitpe11 Co-authored-by: Shjosan Co-authored-by: Swyter Co-authored-by: Uzuki Shimamura Co-authored-by: Vetle Ledaal Co-authored-by: abc0922001 Co-authored-by: altinat Co-authored-by: gallegonovato Co-authored-by: zhongfly --- i18n/src/main/res/values-ar/strings.xml | 16 +-- i18n/src/main/res/values-b+es+419/strings.xml | 105 +++++++++--------- i18n/src/main/res/values-be/strings.xml | 2 - i18n/src/main/res/values-bg/strings.xml | 4 - i18n/src/main/res/values-bn/strings.xml | 3 - i18n/src/main/res/values-ca/strings.xml | 21 ++-- i18n/src/main/res/values-ceb/strings.xml | 2 - i18n/src/main/res/values-cs/strings.xml | 11 +- i18n/src/main/res/values-cv/strings.xml | 13 +-- i18n/src/main/res/values-de/strings.xml | 27 ++--- i18n/src/main/res/values-el/strings.xml | 11 +- i18n/src/main/res/values-eo/strings.xml | 2 - i18n/src/main/res/values-es/strings.xml | 35 +++--- i18n/src/main/res/values-eu/strings.xml | 3 - i18n/src/main/res/values-fa/strings.xml | 3 - i18n/src/main/res/values-fi/strings.xml | 4 - i18n/src/main/res/values-fil/strings.xml | 30 ++--- i18n/src/main/res/values-fr/strings.xml | 4 - i18n/src/main/res/values-gl/strings.xml | 4 - i18n/src/main/res/values-he/strings.xml | 4 - i18n/src/main/res/values-hi/strings.xml | 4 - i18n/src/main/res/values-hr/strings.xml | 18 +-- i18n/src/main/res/values-hu/strings.xml | 4 - i18n/src/main/res/values-in/strings.xml | 4 - i18n/src/main/res/values-it/strings.xml | 11 +- i18n/src/main/res/values-ja/strings.xml | 12 +- i18n/src/main/res/values-jv/strings.xml | 2 - i18n/src/main/res/values-kk/strings.xml | 4 - i18n/src/main/res/values-kn/strings.xml | 2 - i18n/src/main/res/values-ko/strings.xml | 4 - i18n/src/main/res/values-lt/strings.xml | 4 - i18n/src/main/res/values-lv/strings.xml | 4 - i18n/src/main/res/values-ms/strings.xml | 4 - i18n/src/main/res/values-nb-rNO/strings.xml | 23 ++-- i18n/src/main/res/values-ne/strings.xml | 25 +++-- i18n/src/main/res/values-nl/strings.xml | 4 - i18n/src/main/res/values-pl/strings.xml | 6 +- i18n/src/main/res/values-pt-rBR/strings.xml | 12 +- i18n/src/main/res/values-pt/strings.xml | 6 +- i18n/src/main/res/values-ro/strings.xml | 4 - i18n/src/main/res/values-ru/strings.xml | 12 +- i18n/src/main/res/values-sa/strings.xml | 3 - i18n/src/main/res/values-sc/strings.xml | 4 - i18n/src/main/res/values-sdh/strings.xml | 3 - i18n/src/main/res/values-sk/strings.xml | 4 - i18n/src/main/res/values-sq/strings.xml | 4 - i18n/src/main/res/values-sr/strings.xml | 4 - i18n/src/main/res/values-sv/strings.xml | 27 +++-- i18n/src/main/res/values-th/strings.xml | 11 +- i18n/src/main/res/values-tr/strings.xml | 4 - i18n/src/main/res/values-uk/strings.xml | 4 - i18n/src/main/res/values-uz/strings.xml | 3 - i18n/src/main/res/values-vi/strings.xml | 6 +- i18n/src/main/res/values-zh-rCN/strings.xml | 6 +- i18n/src/main/res/values-zh-rTW/strings.xml | 24 ++-- 55 files changed, 242 insertions(+), 338 deletions(-) diff --git a/i18n/src/main/res/values-ar/strings.xml b/i18n/src/main/res/values-ar/strings.xml index 09d7ac2fd..7c03eb3a7 100644 --- a/i18n/src/main/res/values-ar/strings.xml +++ b/i18n/src/main/res/values-ar/strings.xml @@ -154,7 +154,7 @@ تم محو ملفات تعريف الارتباط محو قاعدة البيانات مسح سجلّ الإدخالات التي ليست محفوظة في مكتبتك - هل أنت متأكد؟ الفصول المقروءة ومستوى التقدم للإدخالات الغير الموجودة في مكتبتك سيتم فقده + أمتأكِّد؟ إن فعلتَ خسرتَ الفصول المقروءة وسير القراءة تم حذف المدخلات تحديث بيانات التتبع تحديث الحالة، والتقييم، وآخر فصل: عن طريق خدمات التتبع @@ -569,8 +569,6 @@ رأسي التدوير تلقائيًّا - إنشاء مجلدات وفقا لعنوان الإدخالات - حفظ الصفحات في مجلدات منفصلة الإجراءات تدرج رمادي إستثناء: %s @@ -619,7 +617,6 @@ ين & يانغ تاكو ديناميك - جار تحديث المكتبة…( (%2$d) / (%1$d) ) تقوم بعض الشركات المصنعة بوضع قيود إضافية على التطبيقات التي قد تقضي على الخدمات التي تعمل في الخلفية. يحتوي هذا الموقع على مزيد من المعلومات حول كيفية إصلاحه. قد لا يعمل النسخ الاحتياطيُّ أو الاستعادة إن عطِّلت أمثَلَة MIUI. يُحسِّن مصادر معينة، وتُتابَع المدخلات حال إضافتها للمكتبة. @@ -648,7 +645,7 @@ إجمالي الإدخالات تحذير اللغة - يجب عليك الإحتفاظ بنُسخ في أماكن أخرى أيضًا. + زد على ذلك حفظ الاحتياط في غير هذا المكان، وتنبَّه لوجود الخطير فيها ككلمات السر، وتحفَّظ من مشاركتها. التحديثات الكبيرة تضر بالمصادر، وتؤدي لتحديثات أبطأ، وقد تسبب زيادة في استهلاك البطارية۔ اضغط لمعرفة المزيد۔ التسجيل المطول معلومات التطبيق @@ -670,7 +667,7 @@ قياسي امسح ملفات التخزين المؤقت عند فتح التطبيق لا شئ للتنظيف - %1$d عدد الإدخالات غير المتواجدة بقاعدة بيانات المكتبه + %1$d مدخلةً في قاعدة البيانات وليست في المكتبة فشل الحصول على قائمة الملحقات ثبِّت «شيزوكو» وشغِّله لتستخدمه مثبِّت إضافات. تحذير: يمكن أن تؤدِّي التنزيلات كبيرة الحجم والعدد إلى إبطاء المصادر، وقد يُحظر Tachiyomi منها بسبب ذلك. اضغط لمعرفة المزيد۔ @@ -735,7 +732,6 @@ تنسيق RARv5 ليس مدعومًا موجة مد و جزر متعدد - إنقسام الصور الطويلة (بيتا) هنالك تحديث جارٍ بالفعل التنزيل المسبق ينفع حين كون الفصل الحاليِّ والذي يليه منزَّلين. @@ -884,4 +880,10 @@ انقل السلسلة للقعر التوقيت النسبي «%1$s» بدلًا عن «%2$s» + رتِّب الفئات + تُنعَش المكتبة… (%s) + أتريد ترتيب الفئات حسب الحروف؟ + إعدادات المصادر + إعدادات التطبيق + ما استطاع محدِّد الملفات من إدخال الملف في التطبيق \ No newline at end of file diff --git a/i18n/src/main/res/values-b+es+419/strings.xml b/i18n/src/main/res/values-b+es+419/strings.xml index 8f4131c86..fc1ec51dc 100644 --- a/i18n/src/main/res/values-b+es+419/strings.xml +++ b/i18n/src/main/res/values-b+es+419/strings.xml @@ -3,7 +3,7 @@ Cancelar Invertir selección Capítulo más reciente - Total de capítulos + Capítulos totales Información de la extensión Copia de seguridad y restauración Historial @@ -14,7 +14,7 @@ Abrir en el navegador Reanudar Remover - Próximo capítulo + Capítulo siguiente Capítulo anterior Pausar Renombrar categoría @@ -36,14 +36,14 @@ Remover filtro Filtrar Menú - Configuración + Ajustes Capítulos Manga Categorías No hay categorías. Presione el botón de más para crear una y organizar tu biblioteca. Tu biblioteca está vacía Ninguna lectura reciente - No hay actualizaciones + Sin actualizaciones recientes No hay descargas Ayuda Extensiones @@ -65,12 +65,12 @@ Guardar Compartir Instalar - Mover al fondo - Mover hacia arriba - Antigüo + Mover al final + Mover al principio + Menos reciente Cancelar todo Desactivar - Mostrar pestaña de categorías + Mostrar pestañas de categoría Mostrar Modo de visualización Actualice la aplicación WebView para mejor compatibilidad @@ -187,19 +187,19 @@ Preguntar siempre Categoría por defecto - Comprobar nueva portada y los detalles cuando actualizes la biblioteca + Buscar nueva portada y detalles al actualizar la biblioteca Actualizar metadatos automáticamente - Que ya están completadas - Cuando carga + Con estado \"Finalizado\" + Mientras se carga Restricciones de actualización automática - Semanal + Cada semana Cada 2 días - Diario + A diario Cada 12 horas Cada 6 horas Desactivado Actualizaciones automáticas - Actualizaciones + Actualización global Horizontal Ambos Vertical @@ -225,11 +225,11 @@ Error al descargar Toca para instalar la actualización Descargando… - En vertical + Vertical Tamaño de cuadrícula - Monitor + Mostrar Ocultar contenido de la notificación - Ocultar contenido de la aplicación al cambiar entre aplicaciones y bloquear las capturas de pantalla + Pantalla segura oculta el contenido de la aplicación al cambiar entre aplicaciones y bloquea las capturas de pantalla Pantalla segura Después de %1$s minuto @@ -243,8 +243,8 @@ Seguridad y privacidad Gestionar notificaciones Formato de fecha - Encendido - Apagado + Activado + Desactivado Usar el del sistema Modo oscuro Acerca de @@ -261,9 +261,9 @@ Atrás Restaurar Abrir registro - Más nuevo + Más reciente Ordenar - No fijar + Desfijar Fijar Capítulos descargados Cuadrícula cómoda @@ -475,7 +475,7 @@ Eliminar capítulos Las fuentes de esta extensión pueden contener contenido NSFW (18+) 18+ - Esto no evita que las extensiones no oficiales o potencialmente marcadas incorrectamente muestren contenido para mayores de 18 años dentro de la aplicación. + Esto no evita que las extensiones no oficiales o potencialmente marcadas incorrectamente muestren contenido NSFW (+18) dentro de la aplicación. Omitiendo %d capítulo, fuente no encontrada o ha sido filtrado Omitiendo %d capítulos, fuente no encontrada o han sido filtrados @@ -490,7 +490,7 @@ Ajustes del capítulo Capítulos descargardos Manga en la biblioteca - Opciones de búsqueda + Ajustes de búsqueda Pausar historial de lectura Modo incógnito Limpiar historial @@ -499,7 +499,7 @@ Siguiente página Página previa Guía de migración de fuentes - NSFW (Contenido +18) + Fuentes NSFW (+18) No se encontró ninguna aplicación de selección de archivos Por favor iniciar sesión con MAL de nuevo Mostrar en la lista de fuentes y extensiones @@ -515,18 +515,17 @@ Ascendiente Por número de capítulo Por fecha de subida - Rastreado + Siguiendo Derecha e izquierda Mostrar cantidad de elementos Ninguno - Presione para ver detalles del error + Presione para ver detalles Descarga automática Horizontal En vertical 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 @@ -537,7 +536,6 @@ \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 @@ -545,21 +543,20 @@ Incluir: %s Dividir la página partida en la dirección contraria Mostrar el diseño de la zona de toque - Los manga en las categorías excluidas no se actualizarán aún cuando estén en las categorías incluidas. + Los manga en categorías excluidas no se actualizarán aún cuando estén en categorías incluidas. No leído Fuente incompatible Descargar ahora Manga local Por defecto - Autentificar para confirmar cambios + Autenticar para confirmar cambios Los manga en categorías excluidas no se descargara, incluso si estos tambien están en las categorías incluidas. La copia de seguridad y restauración pueden no funcionar correctamente si la Optimización de MIUI está deshabilitada. - Verde manzana + Manzana Verde Cancelar todo para esta serie - Establecer el tipo de orden para cada categoría + Ajustes de orden por categoría Todavía no tienes categorias. Guía de inicio rápido - Actualizando bibloteca… (%1$d de %2$d) No se ha encontrado ninguna coincidencia Error al compartir la portada Error al guardar la portada @@ -588,7 +585,7 @@ Desactivado Activado Si la partición de la página ancha no coincide con la dirección de lectura - Actualizar rastreadores cuando se actualice la biblioteca + Actualizar rastreadores al actualizar la biblioteca Actualizar rastreadores automáticamente Restricciones: %s @@ -597,15 +594,15 @@ Hace %1$d dias Hoy - Modo oscuro con negro puro + Modo oscuro (negro puro) Yotsuba Yin y Yang Turquesa Tako - Daiquirí de fresa + Daiquirí de Fresa Medianoche Dinámico - Tema de la app + Tema de la aplicación Apariencia Fecha de obtención del capítulo Información de la aplicación @@ -633,12 +630,12 @@ Si necesitas ayuda arreglando errores en la actualización de la biblioteca, ve a %1$s Guardar como archivo CBZ Con capitulo(s) sin leer - Omitir actualización de los manga + Omitir actualizar manga Error al obtener la lista de extensiones Advertencia: las descargas en masa pueden causar lentitud en las fuentes y/o bloquear Tachiyomi. Toca para conocer más. Advertencia: las actualizaciones grandes afectan las fuentes y podría hacerlas más lentas, además de un mayor uso de batería. Toca para conocer más. Mostrar manga - Portada-única de la cuadrícula + Solo portadas Preguntas frecuentes y guías %1$d manga que no pertenece a la biblioteca en la base de datos Imagenes panorámicas @@ -652,7 +649,7 @@ %1$d actualización(es) fallida(s) %1$d actualización(es) omitida(s) Retrato inverso - Mover la serie al principio + Mover serie al principio Desactivado No hay entradas para respaldar en la biblioteca Se han limpiado los datos del WebView @@ -681,17 +678,16 @@ Lista inconclusa Lista de espera Lista de lectura - Solo en red sin medidor + Solo en conexiones no medidas Portada Personalizada Imposible abrir el último capítulo leído - Error interno: Chequea los registros del fallo para más información + Error interno: Revisa los registros de fallos para más información Borrar categoría ¿Quieres borrar la categoría %s\? Lavanda Idioma de la aplicación Sin descripción No instalada - Dividir imágenes altas (BETA) Descargar por adelantado Remover todo @@ -707,7 +703,7 @@ Empezados Local Descargados - No ahora + Ahora no Abrir manga aleatorio Saltado porque el manga no requiere actualización No se encontraron entradas en esta categoría @@ -716,8 +712,8 @@ Descargas automáticas y por adelantado Fuentes, extensiones, búsqueda global Respaldo manual y automático - Bloqueo aplicación, pantalla de seguridad - Volcar historial de cuelge, optimizaciones de bateria + Bloqueo de aplicación, pantalla de seguridad + Guardar registros de fallo, optimizaciones de bateria Sincronización de progreso unidireccional, sincronización mejorada Varios idiomas Permiso de almacenamiento no garantizado @@ -766,7 +762,7 @@ Nombre de navegador a usar El formato RARv5 no es soportado Categoría vacía - Mostrar conteo de no leídos en icono de actualizaciónes + Mostrar conteo de no leídos en el ícono de actualizaciones Copiado al portapapeles Saltar capítulos duplicados @@ -781,15 +777,15 @@ \n¿Deseas continuar\? *requerido Disponible, pero la fuente no está instalada: %s - Copiado al portapapeles - Eliminar descargado + Copiar al portapapeles + Eliminar descargados Fuera del período de publicación esperado Deslizar a la izquierda Personalizar intervalo Tocar dos veces para ampliar - Búsqueda mensual (28 días) + Obtención mensual (28 días) Establecer intervalo - Intervalo de búsqueda personalizado + Intervalo de obtención personalizado Próxima actualización prevista %d por fila Intervalos @@ -833,7 +829,12 @@ Inicio de sesión del rastreador No se pudo acceder a %s Desbloquear %s - Mover series al final + Mover serie al final Marcas de tiempo relativas \"%1$s\" en lugar de \"%2$s\" + Ordenar categorías + Actualizando biblioteca… (%s) + Categorías + Configuraciónes de fuente + Configuraciones \ 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 1cefa0e7b..0a9ac827b 100644 --- a/i18n/src/main/res/values-be/strings.xml +++ b/i18n/src/main/res/values-be/strings.xml @@ -229,8 +229,6 @@ Шэры Белы Колер фону - Ствараць тэчкі ў адпаведнасці з назвай мангі - Захоўваць старонкі ў асобныя тэчкі Паказаць пры доўгім націску Дзеяння Абодва diff --git a/i18n/src/main/res/values-bg/strings.xml b/i18n/src/main/res/values-bg/strings.xml index 097115845..6154d960c 100644 --- a/i18n/src/main/res/values-bg/strings.xml +++ b/i18n/src/main/res/values-bg/strings.xml @@ -535,12 +535,10 @@ Пейзаж Работа на заден план Изключи инкогнито - Обновяване на библиотеката… (%1$d/%2$d) Облик Да L-образно Kindle-подобно - Създава папки според заглавието на мангата Автоматично Обновявай тракерите при обновявания на библиотеката Схема на навигацията @@ -590,7 +588,6 @@ Черно-бяло Инвертирай докосване Действия - Запазвай страниците в отделни папки Дясно и Ляво Ориентация Портрет @@ -670,7 +667,6 @@ Автоматично изтегляне при четене Няма описание Няма заглавия в библиотеката за резервно копие - Разделяй високите изображения (БЕТА) Нулирай режима на четене и ориентацията на всички поредици Сигурни ли сте\? Популярни diff --git a/i18n/src/main/res/values-bn/strings.xml b/i18n/src/main/res/values-bn/strings.xml index 7f3dc3ef9..f785b679d 100644 --- a/i18n/src/main/res/values-bn/strings.xml +++ b/i18n/src/main/res/values-bn/strings.xml @@ -546,8 +546,6 @@ পরবর্তী পূর্ববর্তী স্বয়ংক্রিয় - মাঙ্গা শিরোনাম অনুযায়ী ফোল্ডার তৈরি করে - পৃষ্ঠাগুলি পৃথক ফোল্ডারে সংরক্ষণ করুন ক্রিয়া উল্টানো ধূসর স্কেল @@ -612,7 +610,6 @@ প্রতি ৩ দিন সুধু মাত্র ওয়িফি তে সতর্কতা: বড় আপডেটগুলি উত্সের ক্ষতি করে এবং ধীরগতির আপডেটের দিকে নিয়ে যেতে পারে এবং ব্যাটারি ব্যবহারও বাড়িয়ে দিতে পারে - লাইব্রেরি আপডেট করা হচ্ছে... (%1$d/%2$d) সতর্কতা: বড় আকারের ডাউনলোডের ফলে উৎসগুলি মন্থর হয়ে যেতে পারে এবং/অথবা তাচিওমি ব্লক হয়ে যেতে পারে। আরও জানতে এখানে ট্যাপ করুন। অ্যাপ বন্দ্ধ করার সময় অধ্যায়ের ক্যাশে পরিষ্কার করুন তথ্যশালা পরিষ্কার diff --git a/i18n/src/main/res/values-ca/strings.xml b/i18n/src/main/res/values-ca/strings.xml index 898f7c2c5..45b2684c3 100644 --- a/i18n/src/main/res/values-ca/strings.xml +++ b/i18n/src/main/res/values-ca/strings.xml @@ -156,7 +156,7 @@ Anteantepenúltim capítol llegit Anteanteantepenúltim capítol llegit Baixa capítols nous - Serveis + Serveis de seguiment Crea una còpia de seguretat Es pot utilitzar per a restaurar la biblioteca actual Restaura una còpia de seguretat @@ -409,7 +409,7 @@ %d categoria %d categories - La sincronització és unidireccional per a actualitzar el progrés dels capítols als serveis de seguiment. Configureu el seguiment d’elements individuals al seu botó de seguiment. + La sincronització és unidireccional per a actualitzar el progrés dels capítols als serveis de seguiment externs. Configureu el seguiment d’elements individuals al seu botó de seguiment. Refresca les portades de la biblioteca Aquesta extensió no pertany a la llista d’extensions oficials. No oficial @@ -531,8 +531,6 @@ 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 @@ -565,8 +563,7 @@ La més alta Categories excloses Encara no teniu cap categoria. - S’està actualitzant la biblioteca… (%1$d/%2$d) - Serveis millorats + Serveis de seguiment millorats Ahir Fa %1$d dies @@ -607,7 +604,7 @@ Instal·lador Antic Buida la memòria cau de capítols en obrir l’aplicació - Aquests serveis proporcionen funcionalitats millorades per a fonts específiques. Els elements se segueixen automàticament en afegir-los a la vostra biblioteca. + Proporciona funcionalitats millorades per a fonts específiques. Els elements se segueixen automàticament en afegir-los a la vostra biblioteca. Alguns fabricants tenen restriccions addicionals per a les aplicacions que finalitzen els serveis en segon pla. Aquest lloc web té més informació de com solucionar-ho. Hi ha %1$d elements a la base de dades que no són a la biblioteca Cancel·lada @@ -617,7 +614,7 @@ Omet les actualitzacions dels elements Amb capítols no llegits Desa com a arxiu CBZ - També hauríeu de desar còpies de les còpies de seguretat en altres llocs. + També hauríeu de desar còpies de les còpies de seguretat en altres llocs. Les còpies de seguretat poden contenir dades sensibles, incloent-hi les contrasenyes desades; aneu amb compte si les compartiu. No hi ha res que calgui buidar Imprimeix registres detallats al registre del sistema (redueix el rendiment de l’aplicació) Publicació finalitzada @@ -717,7 +714,6 @@ Reinicia l’aplicació S’ha omès perquè no cal actualitzar la sèrie Suprimireu «%s» de la vostra biblioteca - Divideix les imatges altes (BETA) Cerca… Biblioteca actualitzada per darrera vegada: %s S’estan comprovant les baixades @@ -810,7 +806,7 @@ S’ha completat la sincronització de la biblioteca No s’ha pogut crear un fitxer de còpia de seguretat Llicenciat: no hi ha capítols a mostrar - Inici de sessió al seguiment + Inici de sessió al servei de seguiment S’ha invalidat l\'índex de baixades Premeu aquí per a obtenir ajuda amb el Cloudflare Desbloca %s @@ -820,4 +816,9 @@ Mou la sèrie a baix de tot Marques de temps relatives «%1$s» en comptes de «%2$s» + Ordena les categories + S’està actualitzant la biblioteca… (%s) + Voleu ordenar les categories alfabèticament\? + Configuració de la font + Configuració de 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 81529b94c..aaa60ccf4 100644 --- a/i18n/src/main/res/values-ceb/strings.xml +++ b/i18n/src/main/res/values-ceb/strings.xml @@ -242,8 +242,6 @@ 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 a1ba82993..10f2a3842 100644 --- a/i18n/src/main/res/values-cs/strings.xml +++ b/i18n/src/main/res/values-cs/strings.xml @@ -539,8 +539,6 @@ 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 @@ -569,7 +567,6 @@ Nastavení řazení pro jednotlivé kategorie Nemáte žádné kategorie. Začít stahovat nyní - Aktualizuji knihovnu… (%1$d / %2$d) Někteří výrobci používají další omezení aplikací, která vypíná služby na pozadí. Na této webové stránce najdete další informace o tom, jak to opravit. Pokud je MIUI optimalizace vypnutá, zálohování/obnovování nemusí fungovat správně. Poskytují rozšířené funkce pro konkrétní zdroje. Záznamy jsou po přidání do knihovny automaticky sledovány. @@ -613,7 +610,7 @@ Info o Aplikaci Invertované Varování - Kopie záloh by jste také měli uchovat na více místech. + Kopie záloh by jste také měli uchovat na více místech. Zálohy mohou obsahovat citlivé informace včetně jakýchkoliv uložených hesel; buďte opatrní při sdílení. Celkem položek Vybrat obráceně Jazyk @@ -711,7 +708,6 @@ Jste si jistí\? Chystáte se odstranit \"%s\" ze své knihovny Více - Rozdělit vysoké obrázky (BETA) Poslední aktualizace knihovny: %s Populární Nebyla udělena oprávnění k úložišti @@ -836,4 +832,9 @@ Přesunout sérii na konec Relativní časová razítka \"%1$s\" namísto \"%2$s\" + Nastavení aplikace + Nastavení zdroje + Aktualizace knihovny... (%s) + Seřadit kategorie + Chtěli by jste seřadit kategorie abecedně\? \ No newline at end of file diff --git a/i18n/src/main/res/values-cv/strings.xml b/i18n/src/main/res/values-cv/strings.xml index f80d926e7..ff432c11b 100644 --- a/i18n/src/main/res/values-cv/strings.xml +++ b/i18n/src/main/res/values-cv/strings.xml @@ -7,7 +7,7 @@ Тетел %02d минут та %02d ҫеккунт Сервиссем - Ҫӗнӗ сыпӑксене тиесе илмелле + Ҫӗнӗ сыпӑксене тийесе илмелле Юлашки вуланӑ сыпăк Сӳнтернӗ Вуланӑ хыҫҫӑн @@ -278,7 +278,7 @@ Сыпӑксен ҫӗнетӗвӗсем Яланхи Тийеве вӑхӑтлӑха чарнӑ - Кӗтмен йӑнӑша пула сыпӑксене тиесе илеймест + Кӗтмен йӑнӑша пула сыпӑксене тийесе илеймест Тийевҫӗ Tachiyomi валли WebView кирлӗ @@ -306,7 +306,7 @@ Ҫӗнӗ сыпӑксем %d хайлав валли тупӑннӑ Ҫӗнӗ сыпӑксен пуррине тӗрӗслени - Сыпӑксене тиесе илес ҫук. Тийевсем пайӗнче ҫӗнӗрен хӑтланса пӑхма пултаратӑн + Сыпӑксене тийесе илме пулмасть. Тийевсем пайӗнче ҫӗнӗрен хӑтланса пӑхма пултаратӑн Ӑтавла Куҫар Куҫарма ҫӑл куҫ суйла @@ -503,7 +503,7 @@ Тийесе илни вӑхӑчӗпе Йӗрленет Файлсенчи йӑнӑшсен логсене хатерлевҫӗсем патне яма упрать - Тухса кайни инчен логсене тиесе яни + Йӑнӑш кӗнекине тийесе йар Куҫӑм палли Сылтӑмран сулахаялла Анлӑ елсене пайлани вулав майлӑ мар пулсан @@ -515,7 +515,7 @@ Малалли Унченхи HTTPS урлӑ DNS - Хӑй хальлӗн тиени + Хӑй хальлӗн тийени Кӑлар: %s Кӗрт: %s Ҫук @@ -525,8 +525,6 @@ Тӑрӑх Урлӑ Урлӑ-тӑрӑх тӗсӗ - Папкӑсене сери ячӗпе туни - Елсене уйрӑм папкӑсенче упрамалла Тӑвӑмсем Пусма вырӑнсене вулӑш уҫӑ чухне кӑтартмалла Йӑнӑшсене кӑтарт @@ -603,7 +601,6 @@ Сӳнтернӗ Хушмасен йат-йышне илесси пулаймарӗ Вулавӑша ҫӗнетнӗ май йӗрлеве те ҫӗнетни - Вӑрӑм сӑнсене пайлани (ПЕТТӖ) Кашни пухмӑшӑн хӑйӗн ала ӗнерӗвӗсем Ап ҫинчен Вулӑшӑн тухӑҫа лайӑхлатать diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml index b0fa3de59..98eef49ce 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -345,7 +345,7 @@ Überprüfe auf neue Kapitel Akkuverbrauch-Optimierung deaktivieren Hilft bei Bibliotheksaktualisierungen und -sicherungen im Hintergrund - Optimierung des Akkuverbrauchs ist schon deaktiviert + Akkuverbrauch-Optimierung ist bereits deaktiviert E-Mail-Adresse Kapitelübergang immer anzeigen @@ -436,7 +436,7 @@ %1$s Kapitel %1$s Kapitel - Erfordert einen Neustart der Anwendung, um wirksam zu werden + Erfordert einen Neustart der App, um wirksam zu werden Netzwerk Tippzonen umkehren Beide @@ -532,8 +532,6 @@ Kopieren in die Zwischenablage fehlgeschlagen Querformat Hochformat - Erstellt Ordner nach dem Titel der Einträge - Speichere Seiten in separate Ordner Ausrichtung Aktionen Graustufen @@ -561,8 +559,7 @@ Tracking-Anleitung Du hast noch keine Kategorien. Download jetzt starten - Aktualisiere Bibliothek… (%1$d/%2$d) - Einige Hersteller haben zusätzliche Anwendungsbeschränkungen, die Hintergrunddienste stoppen. Diese Webseite hat mehr Informationen darüber, wie man dies beheben kann. + Einige Hersteller haben zusätzliche App-Beschränkungen, die Hintergrunddienste stoppen. Diese Webseite hat mehr Informationen darüber, wie man dies beheben kann. Die Sicherung/Wiederherstellung funktioniert möglicherweise nicht richtig, wenn die MIUI-Optimierung deaktiviert ist. Tiefschwarzer Dunkelmodus Yotsuba @@ -596,7 +593,7 @@ Tablet-Benutzeroberfläche Ausgeschlossene Kategorien Beim Übersetzen mithelfen - Anwendungsinfos + App-Informationen Installiere und starte Shizuku, um Shizuku als Installationsprogramm für Erweiterungen zu verwenden. Shizuku läuft nicht Legacy @@ -604,16 +601,16 @@ Erweiterung wird installiert… Einträge insgesamt Ausführliche Protokollierung - Ausführliche Protokolle im Systemprotokoll ausgeben (verringert die Anwendungsleistung) + Ausführliche Protokolle im Systemprotokoll ausgeben (verringert die App-Leistung) 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. + 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. 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. Alle aktualisieren - Anwendungsaktualisierungen + App-Aktualisierungen Kapitel-Zwischenspeicher beim Öffnen der App löschen %1$d Nicht-Bibliothekseinträge in der Datenbank Nichts zu bereinigen @@ -684,7 +681,7 @@ Alles entfernen Das RARv5-Format wird nicht unterstützt Deine kürzlich aktualisierten Bibliothekseinträge ansehen - Widget nicht verfügbar, wenn die App-Sperre aktiviert ist + Widget ist nicht verfügbar, wenn die App-Sperre aktiviert ist Eine Aktualisierung ist bereits im Gange User-Agent-Text darf nicht leer sein Flutwelle @@ -696,7 +693,6 @@ Funktioniert nur, wenn das aktuelle Kapitel sowie das darauf folgende bereits heruntergeladen sind. Bist du dir sicher\? - Hohe Bilder aufteilen (BETA) Du bist gerade dabei, „%s“ aus deiner Bibliothek zu entfernen Mehrere Sprachen Bibliothek zuletzt aktualisiert: %s @@ -708,7 +704,7 @@ Lesemodus, Anzeige, Navigation Automatische Downloads, im Voraus herunterladen Kategorien, globale Aktualisierungen, Kapitelaktionen - Anwendung neustarten + App neustarten Einweg-Synchronisation, erweiterte Synchronisation Quellen, Erweiterungen, globale Suche Ups! @@ -820,4 +816,9 @@ Serie nach unten verschieben Relative Zeitstempel „%1$s“ anstelle von „%2$s“ + App-Einstellungen + Quelleneinstellungen + Bibliothek wird aktualisiert… (%s) + Kategorien sortieren + Möchtest du die Kategorien alphabetisch sortieren\? \ 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 7439914a0..adbd9ac75 100644 --- a/i18n/src/main/res/values-el/strings.xml +++ b/i18n/src/main/res/values-el/strings.xml @@ -532,8 +532,6 @@ Απέτυχε η αντιγραφή στο πρόχειρο Οριζόντια Κατακόρυφα - Δημιουργεί φακέλους σύμφωνα με τον τίτλο των καταχωρήσεων - Αποθήκευση σελίδων σε ξεχωριστούς φακέλους Ενέργειες Περιστροφή Κλίμακα του γκρι @@ -564,7 +562,6 @@ Midnight Dusk Πράσινο Μήλο Θέμα εφαρμογής - Ενημέρωση βιβλιοθήκης… (%1$d/%2$d) Ορισμένοι κατασκευαστές έχουν πρόσθετους περιορισμούς εφαρμογών που εξουδετερώνουν τις υπηρεσίες παρασκηνίου. Αυτός ο ιστότοπος έχει περισσότερες πληροφορίες για το πώς να το διορθώσετε. Η δημιουργία αντιγράφων ασφαλείας/επαναφορά ενδέχεται να μη λειτουργεί σωστά εάν είναι απενεργοποιημένη η Βελτιστοποίηση MIUI. Απόλυτα μαύρη σκοτεινή λειτουργία @@ -607,7 +604,7 @@ Εκτύπωση λεπτομερών αρχείων καταγραφής στο αρχείο καταγραφής συστήματος (μειώνει την απόδοση της εφαρμογής) Γλώσσα Προειδοποίηση - Θα πρέπει να διατηρείτε αντίγραφα αντιγράφων ασφαλείας και σε άλλα μέρη. + Θα πρέπει να κρατάτε αντίγραφα αντιγράφων ασφαλείας και σε άλλα μέρη. Τα αντίγραφα ασφαλείας ενδέχεται να περιέχουν ευαίσθητα δεδομένα, συμπεριλαμβανομένων τυχόν αποθηκευμένων κωδικών πρόσβασης, να είστε προσεκτικοί αν τα μοιράζεστε. Οι μεγάλες ενημερώσεις βλάπτουν τις πηγές και μπορεί να οδηγήσουν σε πιο αργές ενημερώσεις και σε αυξημένη χρήση της μπαταρίας. Πατήστε για να μάθετε περισσότερα. Μόνο σε Wi-Fi Κάθε 3 ημέρες @@ -696,7 +693,6 @@ Λειτουργεί μόνο εάν το τρέχον κεφάλαιο + το επόμενο έχουν ήδη ληφθεί. Είστε σίγουροι; - Διαχωρισμός ψηλών εικόνων (BETA) Πολλαπλό Δημοφιλή Τελευταία ενημέρωση βιβλιοθήκης: %s @@ -820,4 +816,9 @@ Μετακίνηση σειράς προς τα κάτω Σχετικές χρονικές σημάνσεις \"%1$s\" αντί του \"%2$s\" + Ρυθμίσεις εφαρμογής + Ταξινόμηση κατηγοριών + Ενημέρωση βιβλιοθήκης… (%s) + Θέλετε να ταξινομήσετε τις κατηγορίες αλφαβητικά; + Ρυθμίσεις πηγών \ No newline at end of file diff --git a/i18n/src/main/res/values-eo/strings.xml b/i18n/src/main/res/values-eo/strings.xml index 857703896..d3f4f8a2c 100644 --- a/i18n/src/main/res/values-eo/strings.xml +++ b/i18n/src/main/res/values-eo/strings.xml @@ -409,7 +409,6 @@ Kromaĵaj ĝisdatigoj Elŝutito paŭzigita Elŝutilo - Ĝisdatigas bibliotekon... (%1$d/%2$d) Kontrolas por trovi novajn ĉapitrojn Por ĉi-serion Propra filtrilo @@ -457,7 +456,6 @@ 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 0f8cd0446..77b438159 100644 --- a/i18n/src/main/res/values-es/strings.xml +++ b/i18n/src/main/res/values-es/strings.xml @@ -75,7 +75,7 @@ Negro Sentido de lectura normal Por páginas, de izquierda a derecha - Por páginas, de derecha a izquierda + Páginas (de derecha a izquierda) Por páginas, de arriba abajo Tira vertical continua Método de ampliación @@ -111,7 +111,7 @@ Cookies borradas Borrar la base de datos Borrar el historial de los elementos que no estén guardados en tu biblioteca - ¿Estás seguro\? Se perderán los capítulos leídos y el progreso del los elementos que no estén en la biblioteca + ¿Está seguro\? Se perderán los capítulos leídos y el progreso de las entradas que no pertenezcan a la biblioteca Entradas eliminadas Versión @@ -191,7 +191,7 @@ No se ha podido descargar el capítulo debido a un error inesperado No estás conectado a ninguna red Wi-Fi Categorías - Elementos de la biblioteca + Entradas en la biblioteca Seguimiento Historial Favoritos @@ -411,7 +411,7 @@ Anclar Añadir seguimiento En biblioteca - Añadir a biblioteca + Añadir a la biblioteca Primero instala WebView para poder ver contenido de la aplicación Menos Más @@ -455,9 +455,9 @@ No oficial Datos Fuentes que faltan: - La copia de seguridad no contiene ningún elemento de la biblioteca. + La copia de seguridad no contiene ningun elemento; la biblioteca está vacía. El archivo de copia de respaldo no es correcto - Comprobar si hay una nueva portada y detalles al actualizar la biblioteca + Comprueba si hay una nueva portada, información y descripción al actualizar la biblioteca Actualizar automáticamente los metadatos Cuadrícula amplia Migrar @@ -515,7 +515,7 @@ No hay capítulos Se han actualizado los ajustes predeterminados de capítulo Establecer como predeterminado - Aplicar también a todo el manga en mi biblioteca + Aplicar también a todos los elementos en mi biblioteca ¿Seguro que quieres guardar estos ajustes como predeterminados\? Ajustes de capítulo %1$s: %2$s, página %3$d @@ -575,8 +575,6 @@ 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. @@ -595,7 +593,6 @@ Fuente local Algunos fabricantes tienen restricciones adicionales para aplicaciones que detienen los servicios en segundo plano. Esta página web tiene más información sobre cómo solucionarlo. Todavía no existen categorías. - Actualizando biblioteca… (%1$d/%2$d) No se han encontrado coincidencias Fuente no soportada Sin leer @@ -615,8 +612,8 @@ No Establecer el tipo de orden para cada categoría - Actualizar los servicios de seguimiento al actualizar la biblioteca - Actualizar automáticamente los servicios de seguimiento + 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 @@ -651,7 +648,7 @@ Advertencia Las actualizaciones grandes pueden implicar un mayor uso de la batería y que los distintos servicios bloqueen o ralenticen el acceso a tu dispositivo. Toca aquí para más información. Idioma - Es una buena idea tener copias de respaldo fuera de tu dispositivo. + También deberías guardar las copias de seguridad en otros lugares. Las copias de seguridad pueden contener datos confidenciales, incluidas las contraseñas almacenadas. Solo con Wi-Fi Cada 3 días Advertencia: Las descargas grandes pueden llevar a que las fuentes se vuelvan cada vez más lentas y en casos extremos que los servidores limiten o impidan el acceso a Tachiyomi. Toca aquí para más información. @@ -659,7 +656,7 @@ Actualizaciones de la aplicación Borrar la caché de capítulos al abrir la aplicación Base de datos limpia - Hay %1$d elementos en la base de datos que no están en la biblioteca + %1$d entradas que no pertenecen a la biblioteca en la base de datos No se pudo descargar el listado de extensiones Política de privacidad Con capítulos sin leer @@ -726,7 +723,7 @@ Restablecer el nombre del navegador («user agent») Quitar todo La app no soporta el formato RARv5 - Ver el manga actualizado de forma reciente + Aquí aparecerá el contenido más reciente de tu biblioteca El widget no está disponible cuando el bloqueo de aplicación está activo Ya se está actualizando Marea @@ -740,7 +737,6 @@ Los siguientes %d capítulos sin leer ¿Estás seguro\? - Separar imágenes más altas que anchas (en desarrollo) La biblioteca se actualizó: %s Estás a punto de borrar «%s» de tu biblioteca Populares @@ -797,7 +793,7 @@ %ds Ahora no La categoría está vacía - Mostrar los capítulos por leer en el icono de actualizar + Mostrar el número de capítulos por leer en el icono de actualizaciones Se ha copiado al portapapeles Saltarse los capítulos repetidos Está disponible, pero la fuente todavía no se ha instalado: %s @@ -867,4 +863,9 @@ Mover al último puesto Marcas de tiempo relativas «%1$s» en vez de «%2$s» + Actualizando biblioteca... (%s) + Ajustes de la fuente + Ajustes de la aplicación + Ordenar categorías + ¿Quieres ordenar las categorías de forma alfabética\? \ 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 77162b700..439ccd799 100644 --- a/i18n/src/main/res/values-eu/strings.xml +++ b/i18n/src/main/res/values-eu/strings.xml @@ -304,7 +304,6 @@ Igoera dataren arabera Irudi hau azaleko arte gisa erabili\? Ezin izan dira kapituluak deskargatu memorian leku gutxi dagoelako - Liburutegia eguneratzen… (%1$d/%2$d) Eguneratze handiek bateriaren erabilera areagotzea eta iturriak motelagoak izatea eragin dezakete Deskarga pausatu da Baxua @@ -357,8 +356,6 @@ %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 cb38c0439..4ea639591 100644 --- a/i18n/src/main/res/values-fa/strings.xml +++ b/i18n/src/main/res/values-fa/strings.xml @@ -496,13 +496,11 @@ راست قدیمی نصب کننده - ساخت پوشه بر اساس عنوان ورودی آپدیت همگی فعالیت در پس زمینه مجموع ورودی ها پیش فرض دنبال شده - ذخیره صفحات در پوشه های جداگانه هیچ مورد مشابهی پیدا نشد در حال نصب کردن افزونه … دریافت لیست افزونه ها ناموفق بود @@ -622,7 +620,6 @@ چند آیا می خواهید دسته \"%s\" را حذف کنید؟ حذف دسته - تقسیم تصاویر بلند (آزمایشی) بارگیری شود دانلود خودکار در حین خواندن جستجو… diff --git a/i18n/src/main/res/values-fi/strings.xml b/i18n/src/main/res/values-fi/strings.xml index c97467e5f..d5464ff55 100644 --- a/i18n/src/main/res/values-fi/strings.xml +++ b/i18n/src/main/res/values-fi/strings.xml @@ -532,8 +532,6 @@ Kopiointi leikepöydälle epäonnistui Vaakatasossa Pystysuunnassa - Luo kansioita manga-otsikon mukaan - Tallenna sivut erillisiin kansioihin Toiminnot Kierron tyyppi Harmaasävy @@ -611,7 +609,6 @@ Alhaisin Ei varmuuskopioitavia sarjoja kirjastossa Useampi - Jaa korkeat kuvat (BETA) Panoroi leveitä kuvia napauttamalla Tallenna CBZ-arkistona Zoomaa vaakasuuntaisiin kuviin @@ -667,7 +664,6 @@ Järjestä Kansikuva Virhe jakaessa kansikuvaa - Päivitetään kirjastoa… (%1$d/%2$d) Napauta saadaksesi lisätietoja Ikäluokitus Seurantaopas diff --git a/i18n/src/main/res/values-fil/strings.xml b/i18n/src/main/res/values-fil/strings.xml index bc086ddf6..c5d86d185 100644 --- a/i18n/src/main/res/values-fil/strings.xml +++ b/i18n/src/main/res/values-fil/strings.xml @@ -133,7 +133,7 @@ Piliting nakahiga Piliting nakatayo Malaya - Pag-ikot + Default na pag-ikot Mabilis Normal Walang animasyon @@ -211,7 +211,7 @@ %d (na) kategorya Palaging tanungin - Panimulang lagayan + Default na kategorya Maghanap ng mga bagong cover at detalye kapag nag-a-update ng Aklatan Kusang sariwain ang metadata May \"Kumpleto\" na estado @@ -245,8 +245,8 @@ I-restore ang backup Magagamit para ma-restore ang kasalukuyang Aklatan Mag-backup - Isahang pagsabay (sync) para mai-update ang progress sa mga kabanata sa mga tracking service. Ayusin ang pagta-track para sa mga indibidwal na entry gamit ang button na Pagta-track. - Mga Serbisyo + Isahang pagsabay (sync) para mai-update ang progress sa mga kabanata sa mga external na tracking service. Ayusin ang pagta-track para sa mga indibidwal na entry gamit ang button na Pagta-track. + Mga Tracker I-update ang progress pagkatapos basahin I-download ang mga bagong kabanata Panlima sa huling nabasa @@ -526,14 +526,12 @@ Kasama: %s Wala Hindi ia-update ang mga entry na nasa mga di kasamang kategorya kahit na nasa mga kasamang kategorya rin sila. - Petsa ng pagkuha + Petsa ng pagkuha ng kabanata I-tap para makita ang detalye Di na suportado ang bersyong ito ng Android 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 @@ -561,11 +559,10 @@ Wala ka pang kategorya. Gabay sa pag-track I-download na - Ina-update ang Aklatan... (%1$d/%2$d) May dagdag na mga restriksyon sa app ang ilang mga modelo ng phone na pumapatay sa mga serbisyo sa background. May impormasyon sa site na ito para maayos ang naturang problema. Maaaring hindi gumana nang maayos ang pag-backup/pag-restore kung nakasara ang MIUI optimization. - Mga serbisyong nagbibigay ng mga pinahusay na mga feature para sa ilang mga source. Kusang tina-track ang mga entry kapag naidagdag ito sa iyong aklatan. - Pinahusay na serbisyo + Nagbibigay ng mga pinahusay na mga feature para sa ilang mga source. Kusang tina-track ang mga entry kapag naidagdag ito sa iyong aklatan. + Pinahusay na tracker Hatinggabi Berdeng Mansanas Nagbabago @@ -590,7 +587,7 @@ Teal at Turquoise Hitsura Patotohanan para makumpirma ang pagbabago - Ipaubaya + Default Sundan Gabay sa Pagsisimula Pang-tablet na UI @@ -608,7 +605,7 @@ Babala: Nakasasama ang mga malalaking update sa source at maaaring humantong sa mabagal na update at pagtaas ng paggamit sa baterya. I-tap para matuto pa. Wika Babala - Dapat nagtatabi rin kayo ng mga kopya ng backup sa ibang mga lugar. + Dapat nagtatabi rin kayo ng mga kopya ng backup sa ibang mga lugar. Ang mga backup ay naglalaman ng sensitibong data tulad ng nakaimbak na password; mag-ingat kung ibahagi ito. Sa Wi-Fi lang Kada 3 araw Babala: maaaring humantong sa pagbagal at/o pagharang ng mga source sa Tachiyomi ang mga malalaking maramihang pag-download. I-tap para matuto pa. @@ -699,7 +696,6 @@ Marami Tatanggalin mo na ang \"%s\" mula sa aklatan mo Huling update sa aklatan: %s - Hatiin ang mga matatangkad na larawan (BETA) Sikat Hindi binigay ang mga permiso sa storage Nilaktawan dahil hindi kailangan ang pag-update sa serye @@ -811,7 +807,7 @@ I-tap dito para sa tulong sa Cloudflare Napawalang-bisa ang indise ng mga download Hindi makalikha ng backup file - Pag-login sa tracking + Pag-login sa tracker Lisensyado - Walang mapakitang kabanata I-unlock ang %s Walang koneksyon sa Internet @@ -820,4 +816,10 @@ Ilagay sa ibaba ang serye Mga relatibong timestamp \"%1$s\" sa halip na \"%2$s\" + 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 app + Ang file picker ay nabigo na ibalik ang file sa app \ 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 b6c90e684..2c0388300 100644 --- a/i18n/src/main/res/values-fr/strings.xml +++ b/i18n/src/main/res/values-fr/strings.xml @@ -578,8 +578,6 @@ 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 @@ -606,7 +604,6 @@ Rendre les réglages de tri propres à chaque catégorie Vous n\'avez pas encore de catégories. Commencer à télécharger - Mise à jour de la bibliothèque… (%1$d/%2$d) La sauvegarde/restauration peut ne pas fonctionner correctement si l\'optimisation MIUI est désactivée. Services qui fournissent des fonctionnalités améliorées pour des sources spécifiques. Les entrées sont automatiquement suivies lorsqu\'elles sont ajoutées à votre bibliothèque. Services avancés @@ -744,7 +741,6 @@ Fonctionne seulement si le chapitre actuel et le suivant sont déjà téléchargés. Êtes-vous sûr(e) \? Populaire - Diviser les grandes images (BETA) Multiple Dernière mise à jour de la bibliothèque le : %s Vous êtes sur le point de retirer « %s » de votre bibliothèque diff --git a/i18n/src/main/res/values-gl/strings.xml b/i18n/src/main/res/values-gl/strings.xml index 1b58a9ac9..a325d1886 100644 --- a/i18n/src/main/res/values-gl/strings.xml +++ b/i18n/src/main/res/values-gl/strings.xml @@ -272,8 +272,6 @@ 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 @@ -390,7 +388,6 @@ Error ao compartir a portada Produciuse un erro ao borrar Varios idiomas - Separar as imaxes altas (BETA) Horizontal Esquerda Ampliar a imaxe en horizontal @@ -650,7 +647,6 @@ Non hai ningún capítulo máis Non se puideron cargar as páxinas: %1$s Non se atopou a fonte - Actualizando biblioteca… (%1$d/%2$d) En uso %dd Se necesitas axuda para arranxar os erros de actualización da biblioteca, consulta %1$s diff --git a/i18n/src/main/res/values-he/strings.xml b/i18n/src/main/res/values-he/strings.xml index d419e9157..4ab6a008a 100644 --- a/i18n/src/main/res/values-he/strings.xml +++ b/i18n/src/main/res/values-he/strings.xml @@ -473,7 +473,6 @@ רצועה מוארכת עם רווחים סידור עמודים מאונך הפוך - שמור דפים בתיקיות נפרדות אנכי שניהם פעולות @@ -481,7 +480,6 @@ אוטומטי אפשר מחיקת פרקים שסומנו מנוע - צור תיקיות בהתאם לכותרת הפריטים שירותים המספקים שירותים משופרים למקורות ספציפיים. פריטים יהיו במעקב אוטומטי אחרי הוספה לספרייה שלך. מקורות חסרים: קובץ גיבוי לא תקין @@ -625,7 +623,6 @@ אתה בטוח\? כל ההיסטוריה תמחק. מדריך נדידת מקורות לא ניתן להוריד פרקים כי אין מספיק מקום אחסון - מעדכן ספרייה... (%1$d/%2$d) אזהרה: הורדות גדולות עלולות לגרום להאטה במקורות ו/או לחסימת Tachiyomi. לחץ כדי ללמוד עוד. פורמט פרק לא תקין בהפסקה @@ -713,7 +710,6 @@ ספריה עודכנה לאחרונה ב: %s - פצל תמונות מוארכות (בטא) שטח תמונה רחבה הסתר פריטים שכבר בספרייה הרשאות אחסון לא ניתנו diff --git a/i18n/src/main/res/values-hi/strings.xml b/i18n/src/main/res/values-hi/strings.xml index d4cff453b..2a89cff93 100644 --- a/i18n/src/main/res/values-hi/strings.xml +++ b/i18n/src/main/res/values-hi/strings.xml @@ -566,7 +566,6 @@ शिज़ुकु नहीं चल रहा है उल्टी काला और सफेद - आइटम के शीर्षक अनुसार फोल्डर बनाता है ट्रैकिंग गाइड उन्नत सेवाएं MIUI ऑप्टिमाइज़ेशन अक्षम होने पर बैकअप/पुनर्स्थापना ठीक से काम नहीं कर सकता है। @@ -582,7 +581,6 @@ कवर पेज सहेजने में त्रुटि अपठित कोई मेल नहीं मिला - पुस्तकालय अपडेट हो रही है… (%1$d/%2$d) आपके पास अभी तक कोई श्रेणी नहीं है। परिवर्तन की पुष्टि करने के लिए प्रमाणित करें अध्याय लाई की तिथि @@ -591,7 +589,6 @@ अनुवाद में मदद करें दिनांक कवर पृष्ठ - पृष्ठों को अलग-अलग फ़ोल्डरों में सहेजें बहिष्कृत श्रेणियों की आइटम डाउनलोड नहीं की जाएंगी, भले ही वे शामिल श्रेणियों में भी हों। सिस्टम लॉग में वर्बोज़ लॉग प्रिंट करें (ऐप प्रदर्शन को कम करता है) ऐसी सेवाएँ जो विशिष्ट स्रोतों के लिए उन्नत सुविधाएँ प्रदान करती हैं। आपकी पुस्तकालय में जोड़े जाने पर आइटम को स्वचालित रूप से ट्रैक किया जाता है। @@ -690,7 +687,6 @@ सब कुछ हटा दें लोकप्रिय - लंबी इमेज को विभाजित करें (BETA) टाइडल वेव्ह यूजर एजेंट स्ट्रिंग (User Agent String) खाली नहीं रखा जा सकता मल्टी diff --git a/i18n/src/main/res/values-hr/strings.xml b/i18n/src/main/res/values-hr/strings.xml index d7416aafe..6beb4859d 100644 --- a/i18n/src/main/res/values-hr/strings.xml +++ b/i18n/src/main/res/values-hr/strings.xml @@ -373,8 +373,8 @@ Aktualizira stanje, ocjenu i zadnje pročitano poglavlje iz usluga za praćenje Aktualiziraj praćenje Unosi su izbrisani - Jesi siguran\? Izgubit će se čitanje poglavlja i tijek unosa koji nisu u biblioteci - Brisanje povijesti za unose koji nisu spremljeni u biblioteci + Sigurno\? Pročitana poglavlja i tijek unosa koji nisu u biblioteci će se izgubiti + Izbriši povijest za unose koji nisu spremljeni u biblioteci Isprazni bazu podataka Kolačići su izbrisani Ukloni kolačiće @@ -547,8 +547,6 @@ 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 @@ -610,8 +608,7 @@ Broj unosa u bazi odataka koje nisu u zbirci: %1$d Opširno zapisivanje Ispiši opširan zapis u zapisnik sustava (smanjuje performanse aplikacije) - Aktualiziranje zbirke … (%1$d/%2$d) - Čuvaj sigurnosne kopije i na drugim mjestima. + Čuvaj sigurnosne kopije i na drugim mjestima. Sigurnosne kopije mogu sadržati osjetljive podatke uključujući sve spremljene lozinke; oprez pri dijeljenju podataka. Korisničko sučelje tableta Velika aktualiziranja štete izvorima i mogu usporiti aktualiziranja i povećati potrošnju baterije. Dodirni i saznaj više. Niska @@ -627,7 +624,7 @@ Politika privatnosti Preskoči ažuriranje unosa Neuspjelo preuzimanje popisa proširenja - Instaler + Instalacijski program Stari način Najviša Isključene kategorije @@ -672,7 +669,6 @@ Sljedećih %d nepročitanih poglavlja Zadnja provjera aktualiziranja - Rastavi visoke slike (BETA) Samo na mrežom bez ograničenja Broj nepročitanih Izbriši kategoriju @@ -836,4 +832,10 @@ Pomakni seriju na kraj Relativne vremenske oznake „%1$s” umjesto „%2$s” + Razvrstaj kategorije + Aktualiziranje biblioteke … (%s) + Želiš li razvrstati kategorije po abecedi\? + Program za biranje datoteka nije uspio vratiti datoteku u aplikaciju + Postavke izvora + Postavke aplikacije \ No newline at end of file diff --git a/i18n/src/main/res/values-hu/strings.xml b/i18n/src/main/res/values-hu/strings.xml index 9df1cbc82..b07be9770 100644 --- a/i18n/src/main/res/values-hu/strings.xml +++ b/i18n/src/main/res/values-hu/strings.xml @@ -408,8 +408,6 @@ 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 @@ -490,7 +488,6 @@ Gyorsítótár törölve: %1$d fájl lett törölve Hiba történt törlés közben Biztos benne\? Nem könyvtári elemek olvasott fejezetei elvesznek - Könyvtár frissítése...(%1$d/%2$d) %d-nak/nek %d-nak/nek @@ -708,7 +705,6 @@ Összeomlás naplók kiírása, akkumulátor optimalizálások Hibás hely: %s Csak akkor működik, ha az aktuális és a következő fejezet már letöltött. - Magas képek felosztása (BÉTA) Letöltés előre Olvasó mód, kijelző, navigáció Szökőár diff --git a/i18n/src/main/res/values-in/strings.xml b/i18n/src/main/res/values-in/strings.xml index cff2bb024..a83de2d60 100644 --- a/i18n/src/main/res/values-in/strings.xml +++ b/i18n/src/main/res/values-in/strings.xml @@ -502,8 +502,6 @@ Lanjut Sblm Otomatis - Simpan halaman di folder terpisah - Membuat folder sesuai dengan judul entri Kecuali: %s Termasuk: %s Membagi halaman lebar @@ -549,7 +547,6 @@ Anda belum memiliki kategori apapun. Mulai mengunduh sekarang Beberapa pabrikan mempunyai batasan aplikasi tambahan yang mematikan layanan latar belakang. Website ini memiliki info lebih lanjut untuk memperbaikinya. - Memperbarui pustaka... (%1$d/%2$d) Pencadangan/pemulihan mungkin tidak berfungsi jika Optimisasi MIUI dimatikan. Menyediakan fitur yang disempurnakan untuk sumber tertentu. Entri secara otomatis dilacak ketika ditambahkan ke perpustakaan Anda. Pelacak yang ditingkatkan @@ -685,7 +682,6 @@ Kamu akan menghapus \"%s\" dari pustaka Pustaka terakhir diperbarui: %s banyak - Potong gambar panjang (BETA) Apa kamu yakin\? Populer Izin penyimpanan tidak diberikan diff --git a/i18n/src/main/res/values-it/strings.xml b/i18n/src/main/res/values-it/strings.xml index c4151930e..4c63d836a 100644 --- a/i18n/src/main/res/values-it/strings.xml +++ b/i18n/src/main/res/values-it/strings.xml @@ -579,9 +579,7 @@ 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 @@ -606,7 +604,6 @@ 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. - Aggiornando libreria... (%1$d/%2$d) Più basso Basso Alto @@ -652,7 +649,7 @@ Registrazione dettagliata Lingua Attenzione - Dovresti tenere delle copie dei backup anche in altri posti. + Dovresti tenere delle copie dei backup anche in altri posti. I backup possono contenere dati sensibili comprese le password memorizzate; fate attenzione al condividerli. Grossi aggiornamenti danneggiano le fonti, possono rallentare gli aggiornamenti e aumentare il consumo di batteria. Tocca per saperne di più. Solo su Wi-Fi Ogni 3 giorni @@ -744,7 +741,6 @@ Sei sicuro\? Multiple Ultimo aggiornamento libreria: %s - Dividi immagini alte (BETA) Stai per rimuovere «%s» dalla tua libreria Popolare Autorizzazioni per l\'archiviazione non concesse @@ -869,4 +865,9 @@ Spostare la serie in fondo Timestamp relativi «%1$s» invece di «%2$s» + Impostazioni app + Impostazioni delle fonti + Aggiornando libreria... (%s) + Ordinamento categorie + Vuoi ordinare le categorie alfabeticamente\? \ 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 9dfee3f0d..4c78f8661 100644 --- a/i18n/src/main/res/values-ja/strings.xml +++ b/i18n/src/main/res/values-ja/strings.xml @@ -535,8 +535,6 @@ 追跡ガイド 画面向き 自動 - 項目のタイトルに基づいてフォルダを作成 - 別々のフォルダにページを保存 操作 グレースケール OFF @@ -558,7 +556,6 @@ 青林檎 アプリテーマ ダウンロードを開始します - ライブラリを更新中... (%1$d/%2$d) ダイナミック 一部のスマホメーカーはバックグラウンドサービスを終了する追加のアプリ制限を施しています。修正する方法についてはこのWebサイトをご覧ください。 バックアップアクティビティ @@ -591,7 +588,7 @@ 拡張機能をインストール中… 高度な追跡サービス 特定ソース専用の高度な機能を提供します。項目はライブラリに追加される時、自動で追跡され始めます。 - ほかの場所にもバックアップのコピーを保管してください。 + ほかの場所にもバックアップのコピーを保管してください。バックアップには保存されたパスワードなどの機密性の高い情報が含まれることがあります。共有時に十分ご注意ください。 システムログにverboseログを出力(アプリのパフォーマンスが低下します) 大規模のアップデートはソースに有害で、ソースを遅くし、電池の消耗を増加する可能性があります。詳しくはタップでご覧ください。 言語 @@ -685,7 +682,6 @@ 本当に実行しますか? 多言語 前回のライブラリ更新:%s - 長い画像の分割(BETA) ライブラリから「%s」を削除しようとしています 人気 ストレージ権限を持っていません @@ -804,4 +800,10 @@ シリーズを底に移動 相対的なタイムスタンプ 「%2$s」の代わりに「%1$s」を使用 + カテゴリの並べ替え + ライブラリの更新中…(%s) + カテゴリをアルファベット順で並べ替えますか? + ソース設定 + アプリ設定 + ファイルピッカーはアプリにファイルを返せませんでした \ No newline at end of file diff --git a/i18n/src/main/res/values-jv/strings.xml b/i18n/src/main/res/values-jv/strings.xml index 14b9636aa..34770500f 100644 --- a/i18n/src/main/res/values-jv/strings.xml +++ b/i18n/src/main/res/values-jv/strings.xml @@ -296,7 +296,6 @@ Kacepetan animasi tutul kaping pindho Walik zona tutul Horisontal - Nggawe folder miturut judhul manga Numpuki Layar Pandhu arah @@ -317,7 +316,6 @@ 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 58d841434..5fc179707 100644 --- a/i18n/src/main/res/values-kk/strings.xml +++ b/i18n/src/main/res/values-kk/strings.xml @@ -292,7 +292,6 @@ Ені бойынша Бастапқы мөлшері Кері портрет - Бумаларды жазбалар атауына сәйкес жасау Көлденең Бүйірлік шегініс Қ @@ -347,7 +346,6 @@ Соңғы оқылғаннан төртінші тарау Қызметтер Сақтық көшірме жасау - Беттерді бөлек бумаларға сақтау Түсқағаз Алдыңғ Биіктігі бойынша @@ -372,7 +370,6 @@ Басу аймағын терістету Тік Kindle тәріздес - Қос үлкен суреттер (Бета) Кітапханадағы жазбаларда ғана жұмыс істейді, сондай-ақ ағымдағы және келесі тарау әлдеқашан жүктелген болса Шеті Дыбыс пернелері @@ -677,7 +674,6 @@ Қай жерден көшетін деректі таңдаңыз Көшіру Қателік пайда болды - Кітапхананы жаңартып жатырмыз… (%1$d/%2$d) Жүктеуіш Файл таңдайтын қолданба табылмады Жаңа нұсқа Tachiyomi сайтында қолжетімді. F-Droid қолданбасының бейресми нұсқасынан көшуді білу үшін басыңыз. diff --git a/i18n/src/main/res/values-kn/strings.xml b/i18n/src/main/res/values-kn/strings.xml index ed01f878f..a554ee16b 100644 --- a/i18n/src/main/res/values-kn/strings.xml +++ b/i18n/src/main/res/values-kn/strings.xml @@ -550,8 +550,6 @@ ಉದ್ದವಾದ ಪುಟ ತಿರುಗುವಿಕೆಯ ಪ್ರಕಾರ ಸ್ವಯಂಚಾಲಿತ - ಮಾಂಗಾ ಶೀರ್ಷಿಕೆಗೆ ಅನುಗುಣವಾಗಿ ಫೋಲ್ಡರ್ ಗಳನ್ನು ರಚಿಸುತ್ತದೆ - ಪ್ರತ್ಯೇಕ ಫೋಲ್ಡರ್ ಗಳಲ್ಲಿ ಪುಟಗಳನ್ನು ಉಳಿಸಿ ಕ್ರಿಯೆಗಳು ಗ್ರೇಸ್ಕೇಲ್ ಆಫ diff --git a/i18n/src/main/res/values-ko/strings.xml b/i18n/src/main/res/values-ko/strings.xml index e41a78f64..fa2cd8cae 100644 --- a/i18n/src/main/res/values-ko/strings.xml +++ b/i18n/src/main/res/values-ko/strings.xml @@ -406,7 +406,6 @@ 소요 시간: %1$s, 발생한 오류: %2$s - 서재 업데이트 중… (%1$d/%2$d) 항목 업데이트 건너뛰기 화면 보안을 켜면 앱을 전환할 때 내용이 숨겨지며 스크린샷을 찍을 수 없습니다 서재에 추가됨 @@ -595,7 +594,6 @@ 읽지 않은 회차가 있는 만화를 건너 뛰었습니다 등록된 카테고리가 없습니다. - 항목 제목에 따라 폴더 생성 소스 이전 설명서 원본 소스를 선택하세요 로컬 소스 @@ -606,7 +604,6 @@ 모두 취소 이 만화의 항목을 모두 취소 앞으로 - 각각의 폴더에 페이지 저장 FAQ 및 설명서 읽지 않음 이 시리즈를 맨 위로 이동 @@ -678,7 +675,6 @@ 사용자 에이전트 문자열은 비워 둘 수 없습니다 미리 다운로드 다언어 - 긴 이미지 분할 (BETA) 서재에서 \"%s\"을(를) 제거하려고 합니다 저장공간 사용 권한이 없음 diff --git a/i18n/src/main/res/values-lt/strings.xml b/i18n/src/main/res/values-lt/strings.xml index 820fc3087..6b24a071c 100644 --- a/i18n/src/main/res/values-lt/strings.xml +++ b/i18n/src/main/res/values-lt/strings.xml @@ -246,8 +246,6 @@ Vertikalus Veiksmai Parodyti ilgiau paspaudus - Išsaugoti puslapius atskiruose aplankuose - Sukuria aplankus pagal įrašo pavadinimą Fono spalva Ankstesnis Pilka @@ -387,7 +385,6 @@ Baigta: Dabartinis: Ieškoma naujų skyrių - Atnaujinama biblioteka... (%1$d/%2$d) Nepavyko atnaujinti %1$d Prieš atlikdami šį veiksmą, pridėkite įrašą į savo biblioteką Praleista, nes nėra perskaitytų skyrių @@ -704,7 +701,6 @@ Kiti %d neskaityti skyriai Kiti %d neskaitytų skyrių - Perskirti aukštus paveikslėlius (BETA versija) Vartotojo agento eilutė negali būti tuščia Atnaujinimas jau vykdomas Biblioteka paskutinį kartą atnaujinta: %s diff --git a/i18n/src/main/res/values-lv/strings.xml b/i18n/src/main/res/values-lv/strings.xml index 899565ddf..f498f0e1a 100644 --- a/i18n/src/main/res/values-lv/strings.xml +++ b/i18n/src/main/res/values-lv/strings.xml @@ -342,7 +342,6 @@ 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 @@ -378,7 +377,6 @@ 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ā @@ -596,7 +594,6 @@ Kļūda, saglabājot attēlu Vāks atjaunināts Nav instalēts - Bibliotēkas atjaunināšana... (%1$d/%2$d) Daudz atjauninājumi kaitē avotiem un var izraisīt lēnākus atjauninājumus un arī lielāku akumulatora lietojumu. Pieskarieties, lai uzzinātu vairāk. Avots nav instalēts: %1$s Pabeigto saraksts @@ -695,7 +692,6 @@ Lasīšanas režīmi, displejs, navigācija Avārijas žurnāli, akumulatora optimizācija Manuālā un automātiskā dublēšana - Sadalīt augstus attēlus (BETA) Paisuma vilnis Vairāku Lejupielādēt uz priekšu diff --git a/i18n/src/main/res/values-ms/strings.xml b/i18n/src/main/res/values-ms/strings.xml index 45fda159a..9dee603f6 100644 --- a/i18n/src/main/res/values-ms/strings.xml +++ b/i18n/src/main/res/values-ms/strings.xml @@ -522,8 +522,6 @@ Landskap Potret Tindakan - Mencipta folder mengikut tajuk entri - Simpan muka surat ke folder berasingan Jenis putaran skrin Skala kelabu Nyahdaya mod inkognito @@ -559,7 +557,6 @@ Dinamik Tema aplikasi Perkidmatan yang menyediakan fungsi yang dipertingkatkan untuk sumber tertentu. Entri akan dijejaki secara automatik apabila ditambahkan ke pustaka. - Mengemaskini pustaka… (%1$d/%2$d) Sandaran/memulih mungkin tidak berfungsi dengan betul jika pengoptimuman MIUI dinyahaktifkan. Sesetengah pengeluar ada sekatan tambahan pada aplikasi yang akan menghentikan perkidmatan latar belakang. Laman web ini ada maklumat cara membaikinya. Pertingkat perkhidmatan @@ -686,7 +683,6 @@ Pelbagai Terakhir pustaka dikemas kini: %s Anda akan membuang \"%s\" ini daripada pustaka anda - Pisah imej panjang (BETA) Popular Kebenaran storan tidak diberikan Dilangkau kerana siri tidak memerlukan kemas kini diff --git a/i18n/src/main/res/values-nb-rNO/strings.xml b/i18n/src/main/res/values-nb-rNO/strings.xml index f1491264b..11dfd4eba 100644 --- a/i18n/src/main/res/values-nb-rNO/strings.xml +++ b/i18n/src/main/res/values-nb-rNO/strings.xml @@ -151,7 +151,7 @@ Fjerde sist leste kapittel Femte sist leste kapittel Last ned nye kapitler - Tjenester + Sporere Opprett sikkerhetskopi Kan brukes til å gjenopprette nåværende bibliotek Gjenopprett sikkerhetskopi @@ -475,7 +475,7 @@ Gjenoppfrisk mangaomslag i biblioteket Sporingstjenester ikke logget inn i: Sikkerhetskopi inneholder ingen bibliotekoppføringer. - Enveissynkronisering for å oppdatere kapittelfremdrift i sporingstjenester. Sett opp sporing for individuelle oppføringer med sporingsknappen. + Enveissynkronisering for å oppdatere kapittelfremdrift i eksterne sporetjenester. Sett opp sporing for individuelle oppføringer med sporingsknappen. Reduserer sjattering, men koster ytelse Sidepolstring Neste side @@ -533,14 +533,11 @@ Liggende Stående Rotasjon - Oppretter mapper i henhold til oppføringenes tittel - Lagre sider i egne mapper Handlinger Oppdater trackere automatisk Helt svart Oppstartsveiledning Du har ingen kategorier enda. - Oppdaterer bibliotek … (%1$d/%2$d) Kilde støttes ikke Ulest Klarte ikke å dele omslag @@ -553,7 +550,7 @@ Fant ikke kapittelet Bakgrunnsaktivitet Spor - Forbedrede tjenester + Forbedret sporere Sporingsveiledning Utelukkede kategorier Laveste @@ -580,7 +577,7 @@ Standard Noen produsenter har ytterligere appbegrensninger som dreper bakgrunnstjenester. Denne nettsiden har mer info om hvordan det kan fikses. Sikkerhetskopier/gjenoppretting kan krangle hvis MIUI-optimalisering er avskrudd. - Tjenester som gir forbedredet funksjoner for spesifikke kilder. Det holdes automatisk øye med oppføringer når de legges til i biblioteket ditt. + Gir forbedredet funksjoner for spesifikke kilder. Det holdes automatisk øye med oppføringer når de legges til i biblioteket ditt. Nettbrettsgrensesnitt Følsomhet for å skjule menyen når du ruller Innstillinger per kategori for sortering @@ -608,7 +605,7 @@ Skriv utfyllende logg til systemloggen (reduserer programytelse) Advarsel Store oppdateringer skader kilder og kan føre til tregere oppdateringer samt økt batteribruk. Trykk for å lære mer. - Du bør oppbevare ekstra kopier av sikkershetskopier andre steder også. + Du bør oppbevare ekstra kopier av sikkershetskopier andre steder også. Sikkerhetskopier kan inneholde sensitiv data, inkludert eventuelle lagrede passord. Vær forsiktig ved deling. Appoppdateringer Hver 3. dag Bare på Wi-Fi @@ -656,7 +653,6 @@ Lavendel Bare på nettverk uten datamåling Språk - Del høye bilder (BETA) Alle leserinnstillinger tilbakestilt Ukjent tittel Ugyldig plassering: %s @@ -812,10 +808,17 @@ Nedlastingsindeksen er ugyldiggjort Kunne ikke opprette en backup-fil Lisensiert - Ingen kapitler å vise - Sporingsinnlogging + Sporerinnlogging Lås opp %s Flytt serien til bunnen Ingen internettforbindelse HTTP %d, sjekk nettsiden i WebView Kunne ikke nå %s + Sorter kategorier + Oppdaterer bibliotek… (%s) + Vil du sortere kategoriene i alfabetisk rekkefølge\? + Kildeinnstillinger + Programinnstillinger + Relative tidsstempler + \"%1$s\" istedenfor \"%2$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 07c53c4d6..9b8f3aa51 100644 --- a/i18n/src/main/res/values-ne/strings.xml +++ b/i18n/src/main/res/values-ne/strings.xml @@ -244,9 +244,7 @@ स्क्रिन डज / चम्किलो जलाउनु / अँध्यारो गर्नु - फरक फोल्डरमा पृष्ठहरू सेभ गर्नुहोस् स्क्रिन अन राख्नुहोस् - इन्ट्रीहरूको शीर्षक अनुसार फोल्डरहरू सिर्जना गर्दछ कुल इन्ट्रीहरू %d वर्ग @@ -316,7 +314,7 @@ पढिसकेपछि प्रगति अपडेट गर्नुहोस् पुस्तकचिनो लगाइएका अध्यायहरू हटाउन अनुमति दिनुहोस् अन्तिम पढिएको अध्याय - सेवाहरू जसले विशिष्ट स्रोतहरूको लागि परिष्कृत सुविधाहरू प्रदान गर्दछ। तपाईंको पुस्तकालयमा इन्ट्री थप्दा स्वतः ट्र्याक गरिन्छ। + विशिष्ट स्रोतहरूको लागि परिष्कृत सुविधाहरू प्रदान गर्दछ। तपाईंको पुस्तकालयमा थप्दा इन्ट्री स्वचालित रूपमा ट्र्याक गरिन्छ। ट्र्याक रिस्टोर सम्पन्न भयो @@ -337,7 +335,7 @@ पोर्ट्रेट फिट उचाइ फिट चौडाइ - सेवाहरू + ट्र्याकर अवैध ब्याकअप फाइल ब्याकअप सिर्जना गरियो ब्याकअप फाइलबाट डेटा रिस्टोर हुनेछ। @@ -346,7 +344,7 @@ रिस्टोर पहिले नै प्रगतिमा छ नेटवर्क ब्याकअप रिस्टोर असफल भयो - तपाईंले ब्याकअपको प्रतिलिपिहरू अन्य ठाउँहरूमा पनि राख्नु पर्छ। + तपाईंले ब्याकअपको प्रतिलिपिहरू अन्य ठाउँहरूमा पनि राख्नु पर्छ। ब्याकअपहरूमा कुनै पनि भण्डारण गरिएका पासवर्डहरू सहित संवेदनशील डेटा समावेश हुन सक्छ; साझा गर्दा होसियार । नयाँ अध्यायहरू फेला पर्यो %1$d नयाँ अध्याय @@ -354,7 +352,7 @@ सबैभन्दा उच्च असक्षम - परिष्कृत सेवाहरू + परिष्कृत ट्र्याकरहरू रिस्टोर रद्द गरियो त्रुटि तन्काउनुहोस् @@ -384,7 +382,7 @@ कुनै Wi-Fi जडान उपलब्ध छैन डाउनलोडहरू रोकियो कुनै नेटवर्क जडान उपलब्ध छैन - ट्र्याकिङ सेवाहरूमा अध्याय प्रगति अपडेट गर्न एकतर्फी सिङ्क। तिनीहरूको ट्र्याकिङ बटनबाट व्यक्तिगत इन्ट्रीहरूको लागि ट्र्याकिङ सेट अप गर्नुहोस्। + बाह्य ट्र्याकर सेवाहरूमा अध्याय प्रगति अपडेट गर्न एक-तर्फी सिङ्क। तिनीहरूको ट्र्याकिङ बटनबाट व्यक्तिगत इन्ट्रीहरूको लागि ट्र्याकिङ सेट अप गर्नुहोस्। ट्र्याकरहरूमा लगइन छैनन्: छुटेको स्रोतहरू: अध्याय क्यास खाली गर्नुहोस् @@ -440,7 +438,7 @@ विकासकर्ताहरूसँग साझेदारी गर्नको लागि फाइलमा त्रुटि लगहरू सेभ गर्दछ ब्याकग्राउण्ड गतिविधि नयाँ के छ - डेटाबेसमा %1$d गैर-पुस्तकालय इन्ट्रीहरू + डेटाबेसमा %1$d गैर-पुस्तकालय इन्ट्रीहरू छन् ब्याट्री अप्टिमाइजेसन पहिले नै असक्षम छ केही निर्माताहरूसँग अतिरिक्त एप प्रतिबन्धहरू छन् जसले ब्याकग्राउण्ड सेवाहरूलाई मार्छ। यो वेबसाइटमा यसलाई कसरी ठीक गर्ने बारे थप जानकारी छ। इन्ट्रीहरू हटाइयो @@ -606,7 +604,6 @@ अघिल्लो अध्याय छैन थोरै जम्मा गर्ने ठाउँ भएको कारणले अध्याय डाउनलोड हुन सकिँदएन सावधान: ठूलो हिस्सामा डाउनलोड गर्नाले स्रोत ढिलो चल्न अनि/वा ताचियोमीलाई अवरुद्घ गर्न सक्नेछ। थप जान्न ट्याप गर्नुहोस्। - पुस्तकालय अपडेट गर्दै...(%1$d/%2$d) ट्र्याकिङ ट्र्याक गर्नुहोस् पढ्दै @@ -658,7 +655,6 @@ पढ्दा स्वत: डाउनलोड गर्नुहोस् म्यानुअल र स्वचालित ब्याकअप एप लक, सुरक्षित स्क्रिन - अग्लो छविहरू विभाजित गर्नुहोस् (BETA) थुप्रै अपडेटहरू आइकनमा नपढिएको गणना देखाउनुहोस् डुप्लिकेट अध्यायहरू छोड्नुहोस् @@ -810,7 +806,7 @@ पुस्तकालय सिङ्क गर्दै डाउनलोड इन्डेक्स अवैध भयो Cloudflare सम्बन्धित मद्दतको लागि यहाँ ट्याप गर्नुहोस् - ट्र्याकिङ लगइन + ट्र्याकर लगइन ब्याकअप फाइल सिर्जना गर्न असफल भयो लाइसेन्स प्राप्त - देखाउन को लागि कुनै अध्याय छैन इन्टरनेट जडान छैन @@ -818,4 +814,11 @@ HTTP %d, WebView मा वेबसाइट जाँच गर्नुहोस् अनलक %s श्रृङ्खलालाई तल सार्नुहोस् + वर्गहरू क्रमबद्ध गर्नुहोस् + पुस्तकालय अपडेट गर्दै... (%s) + के तपाई वर्गहरू वर्णमाला अनुसार क्रमबद्ध गर्न चाहनुहुन्छ\? + स्रोत सेटिङहरू + एप सेटिङहरू + सापेक्ष टाइमस्ट्याम्पहरू + \"%2$s\" को सट्टा \"%1$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 b69b554d1..a36e8e3b8 100644 --- a/i18n/src/main/res/values-nl/strings.xml +++ b/i18n/src/main/res/values-nl/strings.xml @@ -535,8 +535,6 @@ Staand Draaitype Automatisch - Mappen aanmaken op basis van titel - Pagina\'s opslaan in aparte mappen Acties Grijstinten Alles annuleren voor deze serie @@ -561,7 +559,6 @@ Lokale bron Er zijn nog geen categorieën. Begin nu met downloaden - Bibliotheek updaten... (%1$d/%2$d) Sommige fabrikanten hebben extra beperkingen op apps die achtergronddiensten uitschakelen. Informatie over hoe je dit kan oplossen kan je vinden op de deze website. Backup/herstellen werkt waarschijnlijk niet goed als de MIUI Optimalisatie is uitgeschakeld. Puur-zwarte donkere modus @@ -663,7 +660,6 @@ Taal Meerdere Classificatie per leeftijd - Grote afbeeldingen splitsen (BETA) Versie Taal van de applicatie Geen bibliotheek inzendingen om te backuppen diff --git a/i18n/src/main/res/values-pl/strings.xml b/i18n/src/main/res/values-pl/strings.xml index dd1ec001c..42ddf429d 100644 --- a/i18n/src/main/res/values-pl/strings.xml +++ b/i18n/src/main/res/values-pl/strings.xml @@ -299,7 +299,7 @@ Przestarzałe To rozszerzenie nie jest już dostępne i może nie funkcjonować prawidłowo, powodując problemy z aplikacją. Zalecamy odinstalowanie go. Format daty - Aktualizacje + Globalna aktualizacja Wylogować z %1$s\? Wyloguj Wylogowano @@ -560,8 +560,6 @@ 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 @@ -584,7 +582,6 @@ Ograniczenia: %s Niektórzy producenci mają dodatkowe ograniczenia, które zabijają usługi działające w tle. Ta strona zawiera więcej informacji na ten temat. Zacznij pobierać teraz - Aktualizowanie biblioteki… (%1$d/%2$d) Zielone jabłko Dynamiczny Motyw aplikacji @@ -723,7 +720,6 @@ Jesteś pewien\? Działa tylko, jeśli aktualny i następny rozdział są już pobrane. Wielojęzyczne - Dziel wysokie obrazy (BETA) Popularne Biblioteka ostatnio aktualizowana: %s Zamierzasz usunąć \"%s\" ze swojej biblioteki diff --git a/i18n/src/main/res/values-pt-rBR/strings.xml b/i18n/src/main/res/values-pt-rBR/strings.xml index 0d0b9538b..bcebc749c 100644 --- a/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/i18n/src/main/res/values-pt-rBR/strings.xml @@ -543,8 +543,6 @@ 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 @@ -572,7 +570,6 @@ Guia sobre o monitoramento Você não tem categorias ainda. Começar o download agora - Atualizando a biblioteca... (%1$d/%2$d) Algumas fabricantes possuem restrições adicionais de aplicativos que encerram os serviços em segundo plano. Este site possui mais informações sobre como corrigir este problema. O backup e restauração podem não funcionar corretamente se a Otimização da MIUI estiver desabilitada. Modo noturno com preto absoluto @@ -620,7 +617,7 @@ Idioma Atualizações com muitos itens prejudicam as fontes e podem deixar as atualizações lentas e aumentar o uso da bateria. Toque para saber mais. Aviso - Você deve manter cópias em outros locais também. + Você deve manter cópias em outros locais também. Backups podem ter informações sensíveis incluindo senhas salvas; tenha cuidado se compartilhar. Somente no Wi-Fi A cada 3 dias Aviso: grandes downloads em massa podem levar as fontes a ficarem lentas e/ou começarem a bloquear o Tachiyomi. Toque para saber mais. @@ -710,7 +707,6 @@ Você tem certeza\? Múltiplos - Dividir imagens compridas (BETA) Última atualização da biblioteca: %s Você está prestes a remover \"%s\" de sua biblioteca Popular @@ -836,4 +832,10 @@ Mover série para o final Datas relativas \"%1$s\" ao invés de \"%2$s\" + Configurações do aplicativo + Atualizando a biblioteca… (%s) + Configurações das fontes + Ordenar as categorias + Você deseja ordenar as categorias alfabeticamente\? + O seletor de arquivos não retornou o arquivo para o aplicativo \ 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 f0a0dd8e5..34e173676 100644 --- a/i18n/src/main/res/values-pt/strings.xml +++ b/i18n/src/main/res/values-pt/strings.xml @@ -574,8 +574,6 @@ 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 @@ -608,7 +606,6 @@ Yotsuba Fonte local Ainda não tens nenhuma categoria. - Atualizando biblioteca… (%1$d/%2$d) Nenhuma correspondência encontrada 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. @@ -640,7 +637,7 @@ Guardar como ficheiro CBZ %1$d itens que não estão na biblioteca no banco de dados Nada para limpar - Aviso: descargas grandes em massa podem levar as fontes a ficarem lentas e/ou começarem a bloquear o Tachiyomi. Toque para saber mais. + Aviso: downloads grandes em massa podem levar as fontes a ficarem lentas e/ou começarem a bloquear o Tachiyomi. Toque para saber mais. Grandes atualizações prejudicam as fontes e podem levar a atualizações lentas e ainda ao aumento do uso da bateria. Toque para saber mais. Para obter ajuda sobre como corrigir erros de atualização da biblioteca, veja %1$s Limpar a cache de capítulos ao fechar a app @@ -705,7 +702,6 @@ Não foi possível encontrar o caminho do ficheiro da página %d O formato RARv5 não é suportado Multi - Dividir imagens altas (BETA) Transferência automática durante leitura Deseja apagar a categoria \"%s\"\? Apagar categoria diff --git a/i18n/src/main/res/values-ro/strings.xml b/i18n/src/main/res/values-ro/strings.xml index 1fa29539a..778ecfa21 100644 --- a/i18n/src/main/res/values-ro/strings.xml +++ b/i18n/src/main/res/values-ro/strings.xml @@ -654,7 +654,6 @@ Acum %1$d zile Acum %1$d zile - Creează dosare în funcție de titlul intrărilor Automat Pornit @@ -668,7 +667,6 @@ 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. @@ -693,8 +691,6 @@ Tsunami Vârsta minimă Versiune veche - Împărțiți imaginile înalte (BETA) - Actualizăm biblioteca… (%1$d/%2$d) Ghid de urmărire Format portret întors Permisiunile de stocare nu au fost acceptate diff --git a/i18n/src/main/res/values-ru/strings.xml b/i18n/src/main/res/values-ru/strings.xml index 94ac19fe7..1141809a9 100644 --- a/i18n/src/main/res/values-ru/strings.xml +++ b/i18n/src/main/res/values-ru/strings.xml @@ -554,8 +554,6 @@ Не удалось скопировать в буфер обмена Альбомная Портретная - Создавать папки в соответствии с названием серии - Сохранять страницы в отдельные папки Действия Ориентация Оттенки серого @@ -591,7 +589,6 @@ Тако Клубничный Дайкири Полуночные Сумерки - Обновление библиотеки… (%1$d/%2$d) У некоторых производителей есть дополнительные ограничения для приложений, которые убивают фоновые службы. На этом сайте есть более подробная информация о том, как это исправить. Резервная копия/Восстановление может не работать должным образом, если отключена «Оптимизация MIUI». Предоставляет расширенные возможности для определённых источников. Серии будут автоматически отслеживаться при добавлении в библиотеку. @@ -632,7 +629,7 @@ Язык Предупреждение Большое количество обновлений может привести к замедлению работы источников и увеличению расхода батареи. Нажмите для подробностей. - Настоятельно рекомендуется хранить резервные копии в других местах или сервисах. + Настоятельно рекомендуется хранить резервные копии в других местах или сервисах. Резервные копии могут содержать конфиденциальную информацию, как, например, пароли. Будьте осторожны при их отправке. Только по Wi-Fi Каждые 3 дня Предупреждение: Большое количество загрузок может привести к замедлению работы источников и/или блокировке Tachiyomi. Нажмите для подробностей. @@ -724,7 +721,6 @@ Вы уверены\? Многоязыковое Вы собираетесь удалить «%s» из вашей библиотеки - Разделять длинные изображения (БЕТА) Последнее обновление библиотеки: %s Популярное Не предоставлены разрешения на хранение @@ -852,4 +848,10 @@ Переместить серию в конец Относительные временные метки \"%1$s\" вместо \"%2$s\" + Настройки приложения + Настройки источников + Обновление библиотеки... (%s) + Сортировать категории + Хотите ли вы сортировать категории по алфавиту\? + Приложению для выбора файлов не удалось вернуть путь файла в Tachiyomi \ No newline at end of file diff --git a/i18n/src/main/res/values-sa/strings.xml b/i18n/src/main/res/values-sa/strings.xml index 25834e3e2..56b9683a8 100644 --- a/i18n/src/main/res/values-sa/strings.xml +++ b/i18n/src/main/res/values-sa/strings.xml @@ -255,7 +255,6 @@ ऊर्ध्वम् कार्याणि दीर्घस्पर्शने दर्शयतु - पुटानि भिन्नसञ्चयेषु रक्षतु पृष्ठभूमिवर्णः श्वेतः धूसरः @@ -280,7 +279,6 @@ पठितम् इति चिह्नितान् अध्यायान् लङ्घयतु प्रकाशयति द्वयम् - माङ्गाशीर्षकम् अनुसृत्य सञ्चयान् स्रक्ष्यति पृष्ठीकृतम् विस्तारणम् विस्तृतिं समुचितं कुरु @@ -549,7 +547,6 @@ पठनचरित्रं विरमिष्यति समः न लभ्यः मूलस्य सङ्क्रमणमार्गदर्शनम् - ग्रन्थालयं नवीकरोमि… (%1$d/%2$d) \"%1$s\" कृते सार्वत्रिकेण अवेक्षताम् %1$s प्रति अन्तर्गच्छतु %1$s इतः बहिर्गच्छानि किम् diff --git a/i18n/src/main/res/values-sc/strings.xml b/i18n/src/main/res/values-sc/strings.xml index 8f8040bcc..3ad59ed0d 100644 --- a/i18n/src/main/res/values-sc/strings.xml +++ b/i18n/src/main/res/values-sc/strings.xml @@ -533,8 +533,6 @@ 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 @@ -562,7 +560,6 @@ Non tenes galu peruna categoria. Incumintza a iscarrigare como Tako - Agiornende sa biblioteca… (%1$d/%2$d) Sa còpia de seguresa e su riprìstinu diant pòdere non funtzionare comente si tocat si s\'otimizatzione MIUI est disabilitada. Frunit funtzionalidades avantzadas pro fontes ispetzìficas. Sos elementos benint arrastados in manera automàtica cando los annanghes a sa biblioteca tua. Arrastadores avantzados @@ -698,7 +695,6 @@ Seguru ses\? As a bogare \"%s\" dae sa biblioteca tua Mùltiplas - Partzi sas immàgines artas (BETA) Ùrtimu agiornamentu de sa biblioteca: %s Populare Permissu de archiviatzione non cuntzessu diff --git a/i18n/src/main/res/values-sdh/strings.xml b/i18n/src/main/res/values-sdh/strings.xml index 65edfe421..23fdc7a4b 100644 --- a/i18n/src/main/res/values-sdh/strings.xml +++ b/i18n/src/main/res/values-sdh/strings.xml @@ -170,13 +170,11 @@ پیشاندان لە لیستی سەرچاوە و زیادکراوەکان ئەمڕۆ شێوازی پیشاندان - نوێکردنەوەی تۆماری ڕابردوو…( (%2$d) / (%1$d) ) نەرمە لێدانی پێچەوانە هیچ ستوونی هەردووکیان کردارەکان - خەزێنە کردنی لاپەڕەکان لە فۆڵدەری جیاوزدا سپی خۆڵەمێشی پلە پلە پێچەوانەکراو @@ -214,7 +212,6 @@ دەوروبەری لاپەڕە گونجاو بە شاشە ئازاد - درووستکردنی فۆڵدەر بە پێی تایتڵی مانگا ڕەنگی باکگراوند سووچ ڕاست و چەپ diff --git a/i18n/src/main/res/values-sk/strings.xml b/i18n/src/main/res/values-sk/strings.xml index a71d1433c..7422c9dce 100644 --- a/i18n/src/main/res/values-sk/strings.xml +++ b/i18n/src/main/res/values-sk/strings.xml @@ -459,7 +459,6 @@ Zdroj sa nenašiel No, toto je trápne - Aktualizácia knižnice... (%1$d/%2$d) WebView je potrebné pre Tachiyomi Populárne Zoznam čítania @@ -510,7 +509,6 @@ Odstrániť kategóriu Žiadne Zahrnúť: %s - Vytvára priečinky podľa názvu mangy Okraj Vpravo a vľavo Vľavo @@ -573,7 +571,6 @@ 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 @@ -591,7 +588,6 @@ Nenašli sa žiadne kapitoly Informácie o aplikácii Verzia - Rozdelenie vysokých obrázkov (BETA) Zobraziť obsah v oblasti výrezu Horizontálne Zakázané diff --git a/i18n/src/main/res/values-sq/strings.xml b/i18n/src/main/res/values-sq/strings.xml index f992c611b..24288457c 100644 --- a/i18n/src/main/res/values-sq/strings.xml +++ b/i18n/src/main/res/values-sq/strings.xml @@ -274,7 +274,6 @@ Ndani faqet e gjera Inverto vendosjen e faqeve të ndara Nëse vendosja e faqeve të ndara gjerësisht nuk përputhet me drejtimin e leximit - Ndarja e imazheve të gjata (BETA) Shfaq përmbajtjen në zonën e prerjes Prekni dy herë shpejtësia e animacionit Shfaq numrin e faqes @@ -322,7 +321,6 @@ 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 @@ -375,7 +373,6 @@ %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 @@ -521,7 +518,6 @@ Epo, kjo është e sikletshme Nuk është instaluar Kopjo - Biblioteka po përditësohet… (%1$d/%2$d) Kapitulli %1$s dhe %2$d më shumë Kapitujt %1$s Kapitulli %1$s diff --git a/i18n/src/main/res/values-sr/strings.xml b/i18n/src/main/res/values-sr/strings.xml index 0a66772ff..437700083 100644 --- a/i18n/src/main/res/values-sr/strings.xml +++ b/i18n/src/main/res/values-sr/strings.xml @@ -594,8 +594,6 @@ Вертикално Оба Радње - Сачувај странице у засебне фолдере - Прави датотеке по имену наслова У облику слова L Оријентација Усправно @@ -622,7 +620,6 @@ Да ли сте сигурни\? Цела историја ће бити изгубљена. Водич за миграцију извора Упозорење: велики број преузимања може довести до успоравања извора и/или блокирања Tachiyomi-ја. Додирни да сазнаш више. - Ажурирање колекције... (%1$d/%2$d) Велика ажурирања штете изворима и могу довести до споријег ажурирања и повећања потрошње батерије. Кликни да сазнаш више. Ажурирај све Ажурирања апликације @@ -727,7 +724,6 @@ Завршени наслови Побољшава перформансе читача Само на мрежи без ограничења - Раздели високе слике (БЕТА) Дозвола за меморијски простор није одобрена Неважећи низ корисничког агента Није могуће ресетовати подешавања читача diff --git a/i18n/src/main/res/values-sv/strings.xml b/i18n/src/main/res/values-sv/strings.xml index ef030d5de..6790072de 100644 --- a/i18n/src/main/res/values-sv/strings.xml +++ b/i18n/src/main/res/values-sv/strings.xml @@ -156,7 +156,7 @@ Fjärde till sista lästa kapitlet Femte till sist lästa kapitlet Ladda ner nya kapitel - Tjänster + Spårare Skapa säkerhetskopia Kan användas för att återställa biblioteket Återställ säkerhetskopia @@ -178,7 +178,7 @@ Cookies rensade Rensa databas Ta bort historik för inlägg som inte finns i ditt bibliotek - Är du säker\? Lästa kapitel och framsteg för poster som inte är biblioteksinlägg kommer att gå förlorade + Ä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 @@ -410,7 +410,7 @@ Det gick inte att öppna enhetsinställningarna Uppdatera bibliotekets omslag - Envägssynkronisering för att uppdatera kapitlets framsteg i spårningstjänsterna. Ställ in spårning för enskilda inlägg från deras spårningsknapp. + Envägssynkronisering för att uppdatera kapitlets framsteg i externa spårningstjänster. Ställ in spårning för enskilda poster från deras spårningsknapp. Efter uppladdningsdatum Data Saknade källor: @@ -533,8 +533,6 @@ Liggande Porträtt Rotation - Skapa mappar enligt posternas titel - Spara sidor i separata mappar Åtgärder Gråskala Automatisk @@ -561,10 +559,9 @@ Inställningar per kategori för sortering Du har inga kategorier ännu. Börja ladda ner nu - Uppdaterar biblioteket ... (%1$d / %2$d) Säkerhetskopiering/återställning kanske inte fungerar korrekt om MIUI-optimering är inaktiverat. - Tjänster som erbjuder förbättrade funktioner för specifika källor. Inlägg spåras automatiskt när de läggs till i ditt bibliotek. - Förbättrade tjänster + Ger förbättrade funktioner för specifika källor. Poster spåras automatiskt när de läggs till i ditt bibliotek. + Förbättrade spårare Rent svart mörkt läge Yotsuba Yin och yang @@ -604,7 +601,7 @@ Totalt antal inlägg Installera och starta Shizuku för att använda Shizuku som tilläggsinstallationsprogram. Skriv ut utförliga loggar till systemloggen (minskar appprestanda) - Du bör också förvara säkerhetskopiorna på andra ställen. + Du bör även spara kopior av säkerhetskopior på andra platser. Säkerhetskopior kan innehålla känsliga uppgifter, t.ex. lagrade lösenord; var försiktig om du delar dem. Omfattande loggning Varning Språk @@ -615,7 +612,7 @@ Uppdatera alla Appuppdateringar Rensa kapitelcache när appen startas - %1$d poster i databasen som inte är biblioteksposter + %1$d icke-biblioteksposter i databasen Inget att rensa För hjälp med att åtgärda fel i biblioteksuppdateringar, se %1$s Hoppa över uppdatering av poster @@ -699,7 +696,6 @@ Ladda ner i förväg Tidvattenvåg Fungerar endast om det aktuella kapitlet + nästa redan har laddats ner. - Dela stora bilder (BETA) Automatisk nedladdning under läsning Kategorier, global uppdatering, kapitel svepning Läsläge, skärmvisning, navigering @@ -812,10 +808,17 @@ Intervaller Kunde inte skapa en backup-fil Licensierad - Inga kapitel att visa - Spårning av inloggning + Spårar-inloggning Ingen internet anslutning HTTP %d, kolla på webbsida i WebView Kunde inte nå %s Lås upp %s Flytta serien till botten + Sortera kategorier + Uppdaterar biblioteket... (%s) + Vill du sortera kategorierna i alfabetisk ordning\? + Inställningar för källa + Appinställningar + Relativa tidsstämplar + \"%1$s\" istället för \"%2$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 a33e46839..26e3397ee 100644 --- a/i18n/src/main/res/values-th/strings.xml +++ b/i18n/src/main/res/values-th/strings.xml @@ -304,8 +304,6 @@ รูปตัว L อัตโนมัติ เทา - สร้างโฟลเดอร์ตามชื่อเรื่อง - บันทึกหน้าลงในโฟลเดอร์ที่แยกต่างหาก การกระทำ ทั้งสอง แนวตั้ง @@ -567,7 +565,7 @@ %1$d วันที่ผ่านมา ตัวติดตามขั้นสูง - ควรเก็บสำเนาของข้อมูลสำรองไว้ที่อื่นด้วยเช่นกัน + ควรเก็บสำเนาของข้อมูลสำรองไว้ที่อื่นด้วยเช่นกัน การสำรองข้อมูลอาจมีข้อมูลที่ละเอียดอ่อนรวมถึงรหัสผ่านที่เก็บไว้ ควรระวังหากแบ่งปันสำเนา บันทึกบันทึกอย่างละเอียดไปยังบันทึกของระบบ (ลดประสิทธิภาพของแอป) ช่วยแปล รูปแบบตอนไม่ถูกต้อง @@ -609,7 +607,6 @@ ข้อจำกัด: %s เฉพาะขณะเชื่อมต่อ Wi-Fi คำเตือน: การดาวน์โหลดจำนวนมากอาจทำให้แหล่งที่มาทำงานช้าลงและ/หรือปิดกั้น Tachiyomi แตะเพื่อเรียนรู้เพิ่มเติม - กำลังอัปเดตคลัง… (%1$d/%2$d) การอัปเดตจำนวนมากเป็นอันตรายต่อแหล่งที่มาและอาจทำให้การอัปเดตช้าลงและใช้งานแบตเตอรี่เพิ่มขึ้น แตะเพื่อเรียนรู้เพิ่มเติม เผยแพร่จบแล้ว ถูกยกเลิก @@ -684,7 +681,6 @@ แน่ใจแล้วใช่หรือไม่\? หลายภาษา - แบ่งภาพสูงยาว (เบตา) อัปเดตคลังล่าสุด: %s คุณกำลังจะนำ \"%s\" ออกจากคลัง ยอดนิยม @@ -804,4 +800,9 @@ ย้ายเรื่องไปด้านล่าง ประทับเวลาแบบสัมพันธ์กัน แสดง \"%1$s\" แทน \"%2$s\" + จัดเรียงหมวดหมู่ + กำลังอัปเดตคลัง... (%s) + ต้องการจัดเรียงหมวดหมู่ตามตัวอักษรหรือไม่\? + การตั้งค่าแหล่งที่มา + การตั้งค่าแอป \ No newline at end of file diff --git a/i18n/src/main/res/values-tr/strings.xml b/i18n/src/main/res/values-tr/strings.xml index f1f3d3e0c..422f490d9 100644 --- a/i18n/src/main/res/values-tr/strings.xml +++ b/i18n/src/main/res/values-tr/strings.xml @@ -533,8 +533,6 @@ 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 @@ -561,7 +559,6 @@ İzleme kılavuzu Henüz bir kategoriniz yok. Şimdi indirmeye başla - Kitaplık güncelleniyor… (%1$d/%2$d) 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. @@ -699,7 +696,6 @@ \"%s\"yi kitaplığınızdan kaldırmak üzeresiniz Kitaplık son güncelleme zamanı: %s Çoklu - Uzun görselleri böl (BETA) Popüler Depolama izinleri verilmedi Dizi güncelleme gerektirmediği için atlandı diff --git a/i18n/src/main/res/values-uk/strings.xml b/i18n/src/main/res/values-uk/strings.xml index 863ca3c0c..da72e4a33 100644 --- a/i18n/src/main/res/values-uk/strings.xml +++ b/i18n/src/main/res/values-uk/strings.xml @@ -554,8 +554,6 @@ Альбомна Портретна Орієнтація - Створювати теки в відповідності до назви записів - Зберігати сторінки до окремих тек Дії Відтінки сірого Вимкнути режим інкогніто @@ -581,7 +579,6 @@ Обмеження %s Локальне джерело У вашій бібліотеці ще немає категорій. - Оновлення бібліотеки... (%1$d/%2$d) У деяких виробників є додаткові обмеження застосунків, котрі вбивають фонові сервіси. На цьому сайті більше інформації з приводу того, як це виправити. Фонова активність Резервування/Відновлення можуть не працювати належним чином, у випадку, якщо вимкнено Оптимізацію MIUI. @@ -709,7 +706,6 @@ Скинути типовий user agent Формат RARv5 не підтримується Багатомовне - Розділяти високі зображення (БЕТА) Останнє оновлення бібліотеки: %s Доступ до файлової системи не надано diff --git a/i18n/src/main/res/values-uz/strings.xml b/i18n/src/main/res/values-uz/strings.xml index 9b2703dbe..49882925d 100644 --- a/i18n/src/main/res/values-uz/strings.xml +++ b/i18n/src/main/res/values-uz/strings.xml @@ -282,7 +282,6 @@ Yosh cheklovi Faqat cheksiz tarmoq orqali O\'z ichiga oladi: %s - Uzun rasmlarni bo\'lish (BETA) Kesilgan maydondagi ma\'lumotni ko\'rsatish O\'qish rejimini ko\'rsatish Qoplama @@ -294,7 +293,6 @@ Uskuna uchun avtomatik yangilanishlarni cheklash Takrorlanuvchi boblarni o\'tkazib yuborish - Sahifalarni alohida papkalarga saqlash Gorizontal Vertikal Ikkala taraf @@ -317,7 +315,6 @@ 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 e37aebf1b..9574dbd63 100644 --- a/i18n/src/main/res/values-vi/strings.xml +++ b/i18n/src/main/res/values-vi/strings.xml @@ -534,8 +534,6 @@ 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 @@ -580,7 +578,6 @@ 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 - Cập nhật thư viện… (%1$d/%2$d) 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. Chủ đề: Táo Xanh @@ -721,7 +718,6 @@ Thư viện lần cuối được cập nhật:%s Tải Trước Tải trước chỉ áp dụng cho các mục ở trong thư viện và nếu chương cuối cùng đã được tải rồi - Tách các ảnh cao (BETA) Đa Ngôn Ngữ Bỏ qua vì loạt truyện không cần cập nhật Tìm kiếm… @@ -817,4 +813,6 @@ Nhấn vào đây để được trợ giúp về Cloudflare Chưa công bố Mở khoá %s + Cài đặt nguồn + Cài đặt ứng dụng \ 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 2a32f659f..60095fb4d 100644 --- a/i18n/src/main/res/values-zh-rCN/strings.xml +++ b/i18n/src/main/res/values-zh-rCN/strings.xml @@ -521,8 +521,6 @@ 无法复制到剪贴板 横屏 竖屏 - 根据作品标题创建文件夹 - 将图片保存到单独文件夹 操作菜单 屏幕方向 灰度 @@ -550,7 +548,6 @@ 进度记录指南 你还没有任何分类。 立即开始下载 - 正在更新书架… (%1$d/%2$d) 部分制造商会设置额外的应用限制来杀死后台服务。此网站提供了更多有关修复此问题的信息。 如果 MIUI 优化被关闭,备份/还原可能无法正常工作。 纯黑深色模式 @@ -683,7 +680,6 @@ 要求当前章节和下一章节都已下载。 你确定吗? - 分割长图 (测试版) 多语言 书架更新于:%s 即将从书架中删除“%s”。 @@ -800,4 +796,6 @@ 未连接网络 HTTP %d,请在 WebView 中检查网站 无法连接到 %s + 图源设置 + 应用设置 \ No newline at end of file diff --git a/i18n/src/main/res/values-zh-rTW/strings.xml b/i18n/src/main/res/values-zh-rTW/strings.xml index 9fa76f271..a570bf0a5 100644 --- a/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/i18n/src/main/res/values-zh-rTW/strings.xml @@ -262,14 +262,14 @@ 信任 不信任 不信任的擴充套件 - 此擴充功能使用未受信任的憑證簽署,並未啟用。 + 簽署此擴充套件的憑證並不可靠,因此尚未被啟用。 \n -\n惡意擴充功能可能會讀取任何已儲存的登入憑證或執行任意程式碼。 +\n惡意的擴充套件可能會讀取任何已儲存的登入憑證或執行任意的程式碼。 \n -\n通過信任此憑證,您接受這些風險。 +\n若選擇信任該憑證,即表示你願意承擔上述風險。 最後閱畢的章節 最大備份保留數 - 不在書櫃中的作品閱讀進度將被清除,你確定嗎? + 您確定要這樣做嗎?未收藏的漫畫的閱讀進度和章節會被刪除 更新閱讀歷程 與歷程平台同步處理閱讀狀態、評分以及進度 新上架 @@ -520,8 +520,6 @@ \n \n隨後請安裝所有遺失的擴充套件並重新登入各歷程平台。 類別同時屬於「排除」及「包含」的作品,將不會自動下載。 - 儲存頁面至個別資料夾 - 根據作品標題建立資料夾 開始閱讀時,短暫浮現輕觸區域 輕觸區域提示 類別同時屬於「排除」及「包含」的作品,將不會自動更新。 @@ -548,7 +546,6 @@ 已儲存封面 封面 立刻開始下載 - 正在更新書櫃… (%1$d/%2$d) 部分裝置製造商設有額外的應用程式限制來終止背景服務。此網站提供了修復這項問題的詳細資訊。 背景活動 若停用 MIUI 最佳化,備份與還原可能無法正確執行。 @@ -583,7 +580,7 @@ 入門指南 新增 協助翻譯 - 不包括的漫畫類別 + 排除的類別 程式資訊 若要使用 Shizuku 來安裝擴充套件,請先安裝 Shizuku 並開啟之。 傳統 @@ -595,7 +592,7 @@ 警告 大量更新會損害來源,並可能導致更新速度緩慢、電池用量增加。輕觸以瞭解詳情。 錄製詳細記錄 - 你應該在多處保存備份副本。 + 你應該在多處保存備份副本。備份檔可能含有敏感資料 (包括任何已儲存的密碼),分享時請留意。 傾印詳細記錄至系統日誌 (將降低應用程式效能) 僅透過 Wi-Fi 每 3 天 @@ -603,7 +600,7 @@ 全部更新 應用程式更新 啟動應用程式時清除章節快取 - 資料庫中有 %1$d 部作品不屬於藏書 + 資料庫中有 %1$d 個非收藏項目 無須清理 擴充套件清單取得失敗 隱私權政策 @@ -683,7 +680,6 @@ 僅於目前章節及下一章節皆已下載時生效。 你確定嗎? - 分割過高的圖片 (BETA) 多語 即將從書櫃中移除《%s》 書櫃更新於:%s @@ -804,4 +800,10 @@ 置底此作品 相對時間戳記 以「%1$s」表示「%2$s」 + 應用程式設定 + 排序類別 + 正在更新書櫃… (%s) + 欲依照字母順序排列類別嗎? + 來源設定 + 無法將選定的檔案傳回給應用程式 \ No newline at end of file From 489d22720a4343f198c81fe10f69d5b212bfc41a Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 21 Oct 2023 10:04:29 -0400 Subject: [PATCH 26/37] Refresh tracks before updating progress Closes #1652 Also removes the ability to trigger refreshes for the entire library or as part of a library update as it should no longer be needed. Opening the tracking sheet already refreshes the data too, so stale data is irrelevant there. Also closes #4775 since it would no longer be relevant. --- .../domain/track/interactor/TrackChapter.kt | 8 +++-- .../track/service/DelayedTrackingUpdateJob.kt | 22 +++--------- .../track/store/DelayedTrackingStore.kt | 12 +++---- .../settings/screen/SettingsAdvancedScreen.kt | 8 ----- .../settings/screen/SettingsLibraryScreen.kt | 7 ---- .../data/library/LibraryUpdateJob.kt | 35 ------------------- .../library/service/LibraryPreferences.kt | 2 -- i18n/src/main/res/values/strings.xml | 4 --- 8 files changed, 16 insertions(+), 82 deletions(-) diff --git a/app/src/main/java/eu/kanade/domain/track/interactor/TrackChapter.kt b/app/src/main/java/eu/kanade/domain/track/interactor/TrackChapter.kt index fa6245f22..789a784ef 100644 --- a/app/src/main/java/eu/kanade/domain/track/interactor/TrackChapter.kt +++ b/app/src/main/java/eu/kanade/domain/track/interactor/TrackChapter.kt @@ -2,6 +2,7 @@ package eu.kanade.domain.track.interactor import android.content.Context import eu.kanade.domain.track.model.toDbTrack +import eu.kanade.domain.track.model.toDomainTrack import eu.kanade.domain.track.service.DelayedTrackingUpdateJob import eu.kanade.domain.track.store.DelayedTrackingStore import eu.kanade.tachiyomi.data.track.TrackerManager @@ -31,14 +32,17 @@ class TrackChapter( return@mapNotNull null } - val updatedTrack = track.copy(lastChapterRead = chapterNumber) async { runCatching { try { + val updatedTrack = service.refresh(track.toDbTrack()) + .toDomainTrack(idRequired = true)!! + .copy(lastChapterRead = chapterNumber) service.update(updatedTrack.toDbTrack(), true) insertTrack.await(updatedTrack) + delayedTrackingStore.remove(track.id) } catch (e: Exception) { - delayedTrackingStore.addItem(updatedTrack) + delayedTrackingStore.add(track.id, chapterNumber) DelayedTrackingUpdateJob.setupTask(context) throw e } 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 f578bd600..32be14241 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 @@ -8,21 +8,19 @@ import androidx.work.ExistingWorkPolicy import androidx.work.NetworkType import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkerParameters -import eu.kanade.domain.track.model.toDbTrack +import eu.kanade.domain.track.interactor.TrackChapter import eu.kanade.domain.track.store.DelayedTrackingStore -import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.util.system.workManager import logcat.LogPriority import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.system.logcat import tachiyomi.domain.track.interactor.GetTracks -import tachiyomi.domain.track.interactor.InsertTrack import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import kotlin.time.Duration.Companion.minutes import kotlin.time.toJavaDuration -class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters) : +class DelayedTrackingUpdateJob(private val context: Context, workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) { override suspend fun doWork(): Result { @@ -31,9 +29,8 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters) } val getTracks = Injekt.get() - val insertTrack = Injekt.get() + val trackChapter = Injekt.get() - val trackerManager = Injekt.get() val delayedTrackingStore = Injekt.get() withIOContext { @@ -46,17 +43,8 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters) track?.copy(lastChapterRead = it.lastChapterRead.toDouble()) } .forEach { track -> - try { - val service = trackerManager.get(track.syncId) - if (service != null && service.isLoggedIn) { - logcat(LogPriority.DEBUG) { "Updating delayed track item: ${track.id}, last chapter read: ${track.lastChapterRead}" } - service.update(track.toDbTrack(), true) - insertTrack.await(track) - } - delayedTrackingStore.remove(track.id) - } catch (e: Exception) { - logcat(LogPriority.ERROR, e) - } + 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/domain/track/store/DelayedTrackingStore.kt b/app/src/main/java/eu/kanade/domain/track/store/DelayedTrackingStore.kt index d7fc6fa10..5ec27cbea 100644 --- a/app/src/main/java/eu/kanade/domain/track/store/DelayedTrackingStore.kt +++ b/app/src/main/java/eu/kanade/domain/track/store/DelayedTrackingStore.kt @@ -4,7 +4,6 @@ import android.content.Context import androidx.core.content.edit import logcat.LogPriority import tachiyomi.core.util.system.logcat -import tachiyomi.domain.track.model.Track class DelayedTrackingStore(context: Context) { @@ -13,13 +12,12 @@ class DelayedTrackingStore(context: Context) { */ private val preferences = context.getSharedPreferences("tracking_queue", Context.MODE_PRIVATE) - fun addItem(track: Track) { - val trackId = track.id.toString() - val lastChapterRead = preferences.getFloat(trackId, 0f) - if (track.lastChapterRead > lastChapterRead) { - logcat(LogPriority.DEBUG) { "Queuing track item: $trackId, last chapter read: ${track.lastChapterRead}" } + fun add(trackId: Long, lastChapterRead: Double) { + val previousLastChapterRead = preferences.getFloat(trackId.toString(), 0f) + if (lastChapterRead > previousLastChapterRead) { + logcat(LogPriority.DEBUG) { "Queuing track item: $trackId, last chapter read: $lastChapterRead" } preferences.edit { - putFloat(trackId, track.lastChapterRead.toFloat()) + putFloat(trackId.toString(), lastChapterRead.toFloat()) } } } 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 cad067a98..1b5d6a5c3 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt @@ -34,7 +34,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.data.download.DownloadCache import eu.kanade.tachiyomi.data.library.LibraryUpdateJob -import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.network.PREF_DOH_360 @@ -328,7 +327,6 @@ object SettingsAdvancedScreen : SearchableSettings { private fun getLibraryGroup(): Preference.PreferenceGroup { val scope = rememberCoroutineScope() val context = LocalContext.current - val trackerManager = remember { Injekt.get() } return Preference.PreferenceGroup( title = stringResource(R.string.label_library), @@ -337,12 +335,6 @@ object SettingsAdvancedScreen : SearchableSettings { title = stringResource(R.string.pref_refresh_library_covers), onClick = { LibraryUpdateJob.startNow(context, target = LibraryUpdateJob.Target.COVERS) }, ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_refresh_library_tracking), - subtitle = stringResource(R.string.pref_refresh_library_tracking_summary), - enabled = trackerManager.hasLoggedIn(), - onClick = { LibraryUpdateJob.startNow(context, target = LibraryUpdateJob.Target.TRACKING) }, - ), Preference.PreferenceItem.TextPreference( title = stringResource(R.string.pref_reset_viewer_flags), subtitle = stringResource(R.string.pref_reset_viewer_flags_summary), 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 0e71d4cdb..6dc95d6b0 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt @@ -23,7 +23,6 @@ import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.more.settings.widget.TriStateListDialog import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.library.LibraryUpdateJob -import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.ui.category.CategoryScreen import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -197,12 +196,6 @@ object SettingsLibraryScreen : SearchableSettings { title = stringResource(R.string.pref_library_update_refresh_metadata), subtitle = stringResource(R.string.pref_library_update_refresh_metadata_summary), ), - Preference.PreferenceItem.SwitchPreference( - pref = libraryPreferences.autoUpdateTrackers(), - enabled = Injekt.get().hasLoggedIn(), - title = stringResource(R.string.pref_library_update_refresh_trackers), - subtitle = stringResource(R.string.pref_library_update_refresh_trackers_summary), - ), Preference.PreferenceItem.MultiSelectListPreference( pref = libraryPreferences.autoUpdateMangaRestrictions(), title = stringResource(R.string.pref_library_update_manga_restriction), 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 651858332..3554722a0 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 @@ -18,7 +18,6 @@ import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.model.copyFrom import eu.kanade.domain.manga.model.toSManga -import eu.kanade.domain.track.interactor.RefreshTracks import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.download.DownloadManager @@ -89,7 +88,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet private val updateManga: UpdateManga = Injekt.get() private val getCategories: GetCategories = Injekt.get() private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get() - private val refreshTracks: RefreshTracks = Injekt.get() private val fetchInterval: FetchInterval = Injekt.get() private val notifier = LibraryUpdateNotifier(context) @@ -131,7 +129,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet when (target) { Target.CHAPTERS -> updateChapterList() Target.COVERS -> updateCovers() - Target.TRACKING -> updateTrackings() } Result.success() } catch (e: Exception) { @@ -304,10 +301,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet } failedUpdates.add(manga to errorMessage) } - - if (libraryPreferences.autoUpdateTrackers().get()) { - refreshTracks(manga.id) - } } } } @@ -409,33 +402,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet notifier.cancelProgressNotification() } - /** - * Method that updates the metadata of the connected tracking services. It's called in a - * background thread, so it's safe to do heavy operations or network calls here. - */ - private suspend fun updateTrackings() { - coroutineScope { - var progressCount = 0 - - mangaToUpdate.forEach { libraryManga -> - ensureActive() - - val manga = libraryManga.manga - notifier.showProgressNotification(listOf(manga), progressCount++, mangaToUpdate.size) - refreshTracks(manga.id) - } - - notifier.cancelProgressNotification() - } - } - - private suspend fun refreshTracks(mangaId: Long) { - refreshTracks.await(mangaId).forEach { (_, e) -> - // Ignore errors and continue - logcat(LogPriority.ERROR, e) - } - } - private suspend fun withUpdateNotification( updatingManga: CopyOnWriteArrayList, completed: AtomicInteger, @@ -500,7 +466,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet enum class Target { CHAPTERS, // Manga chapters COVERS, // Manga covers - TRACKING, // Tracking metadata } companion object { 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 8c853c759..8edfa7a27 100644 --- a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt @@ -50,8 +50,6 @@ class LibraryPreferences( fun autoUpdateMetadata() = preferenceStore.getBoolean("auto_update_metadata", false) - fun autoUpdateTrackers() = preferenceStore.getBoolean("auto_update_trackers", false) - fun showContinueReadingButton() = preferenceStore.getBoolean( "display_continue_reading_button", false, diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 90eccfd8c..8c7ff8736 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -265,8 +265,6 @@ Automatically refresh metadata Check for new cover and details when updating library - Automatically refresh trackers - Update trackers when updating library Default category Always ask @@ -538,8 +536,6 @@ Clear WebView data WebView data cleared Refresh library covers - Refresh tracking - Updates status, score and last chapter read from the tracking services Reset per-series reader settings Resets reading mode and orientation of all series All reader settings reset From 3a35c13575330e755a81aa550e76c115f69a649a Mon Sep 17 00:00:00 2001 From: Caleb Morris Date: Sat, 21 Oct 2023 14:10:34 -0700 Subject: [PATCH 27/37] Decoupled Tracker Interface (#10042) Split out Tracker to interface and created simple dummy instance for previews --- .../tachiyomi/data/track/BaseTracker.kt | 169 ++++++++++++++++ .../eu/kanade/tachiyomi/data/track/Tracker.kt | 190 ++++-------------- .../tachiyomi/data/track/anilist/Anilist.kt | 4 +- .../tachiyomi/data/track/bangumi/Bangumi.kt | 4 +- .../tachiyomi/data/track/kavita/Kavita.kt | 4 +- .../tachiyomi/data/track/kitsu/Kitsu.kt | 4 +- .../tachiyomi/data/track/komga/Komga.kt | 4 +- .../data/track/mangaupdates/MangaUpdates.kt | 4 +- .../data/track/myanimelist/MyAnimeList.kt | 4 +- .../data/track/shikimori/Shikimori.kt | 4 +- .../tachiyomi/data/track/suwayomi/Suwayomi.kt | 4 +- 11 files changed, 222 insertions(+), 173 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt 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 new file mode 100644 index 000000000..8b152d6cb --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt @@ -0,0 +1,169 @@ +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.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.GetChapterByMangaId +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( + override val id: Long, + override val name: String, +) : Tracker { + + val trackPreferences: TrackPreferences by injectLazy() + val networkService: NetworkHelper by injectLazy() + private val insertTrack: InsertTrack by injectLazy() + private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack by injectLazy() + + override val client: OkHttpClient + get() = networkService.client + + // Application and remote support for reading dates + override val supportsReadingDates: Boolean = false + + // TODO: Store all scores as 10 point in the future maybe? + override fun get10PointScore(track: DomainTrack): Double { + return track.score + } + + override fun indexToScore(index: Int): Float { + return index.toFloat() + } + + @CallSuper + override fun logout() { + trackPreferences.setCredentials(this, "", "") + } + + override val isLoggedIn: Boolean + get() = getUsername().isNotEmpty() && + getPassword().isNotEmpty() + + override fun getUsername() = trackPreferences.trackUsername(this).get() + + override fun getPassword() = trackPreferences.trackPassword(this).get() + + override fun saveCredentials(username: String, password: String) { + 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) + } + } catch (e: Throwable) { + withUIContext { Injekt.get().toast(e.message) } + } + } + + override suspend fun setRemoteStatus(track: Track, status: Int) { + track.status = status + if (track.status == getCompletionStatus() && track.total_chapters != 0) { + track.last_chapter_read = track.total_chapters.toFloat() + } + withIOContext { updateRemote(track) } + } + + override suspend fun setRemoteLastChapterRead(track: Track, chapterNumber: Int) { + if (track.last_chapter_read == 0f && track.last_chapter_read < chapterNumber && track.status != getRereadingStatus()) { + track.status = getReadingStatus() + } + track.last_chapter_read = chapterNumber.toFloat() + if (track.total_chapters != 0 && track.last_chapter_read.toInt() == track.total_chapters) { + track.status = getCompletionStatus() + track.finished_reading_date = System.currentTimeMillis() + } + withIOContext { updateRemote(track) } + } + + override suspend fun setRemoteScore(track: Track, scoreString: String) { + track.score = indexToScore(getScoreList().indexOf(scoreString)) + withIOContext { updateRemote(track) } + } + + override suspend fun setRemoteStartDate(track: Track, epochMillis: Long) { + track.started_reading_date = epochMillis + withIOContext { updateRemote(track) } + } + + override suspend fun setRemoteFinishDate(track: Track, epochMillis: Long) { + track.finished_reading_date = epochMillis + withIOContext { 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) } + } + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt index 490ea0e96..af51d7b80 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt @@ -1,201 +1,81 @@ package eu.kanade.tachiyomi.data.track -import android.app.Application import androidx.annotation.CallSuper import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.annotation.StringRes -import eu.kanade.domain.track.interactor.SyncChapterProgressWithTrack -import eu.kanade.domain.track.model.toDbTrack -import eu.kanade.domain.track.model.toDomainTrack -import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.model.TrackSearch -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.GetChapterByMangaId -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 Tracker(val id: Long, val name: String) { +interface Tracker { - val trackPreferences: TrackPreferences by injectLazy() - val networkService: NetworkHelper by injectLazy() - private val insertTrack: InsertTrack by injectLazy() - private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack by injectLazy() + val id: Long - open val client: OkHttpClient - get() = networkService.client + val name: String + + val client: OkHttpClient // Application and remote support for reading dates - open val supportsReadingDates: Boolean = false - - @DrawableRes - abstract fun getLogo(): Int + val supportsReadingDates: Boolean @ColorInt - abstract fun getLogoColor(): Int + fun getLogoColor(): Int - abstract fun getStatusList(): List + @DrawableRes + fun getLogo(): Int + + fun getStatusList(): List @StringRes - abstract fun getStatus(status: Int): Int? + fun getStatus(status: Int): Int? - abstract fun getReadingStatus(): Int + fun getReadingStatus(): Int - abstract fun getRereadingStatus(): Int + fun getRereadingStatus(): Int - abstract fun getCompletionStatus(): Int + fun getCompletionStatus(): Int - abstract fun getScoreList(): List + fun getScoreList(): List // TODO: Store all scores as 10 point in the future maybe? - open fun get10PointScore(track: DomainTrack): Double { - return track.score - } + fun get10PointScore(track: tachiyomi.domain.track.model.Track): Double - open fun indexToScore(index: Int): Float { - return index.toFloat() - } + fun indexToScore(index: Int): Float - abstract fun displayScore(track: Track): String + fun displayScore(track: Track): String - abstract suspend fun update(track: Track, didReadChapter: Boolean = false): Track + suspend fun update(track: Track, didReadChapter: Boolean = false): Track - abstract suspend fun bind(track: Track, hasReadChapters: Boolean = false): Track + suspend fun bind(track: Track, hasReadChapters: Boolean = false): Track - abstract suspend fun search(query: String): List + suspend fun search(query: String): List - abstract suspend fun refresh(track: Track): Track + suspend fun refresh(track: Track): Track - abstract suspend fun login(username: String, password: String) + suspend fun login(username: String, password: String) @CallSuper - open fun logout() { - trackPreferences.setCredentials(this, "", "") - } + fun logout() - open val isLoggedIn: Boolean - get() = getUsername().isNotEmpty() && - getPassword().isNotEmpty() + val isLoggedIn: Boolean - fun getUsername() = trackPreferences.trackUsername(this).get() + fun getUsername(): String - fun getPassword() = trackPreferences.trackPassword(this).get() + fun getPassword(): String - fun saveCredentials(username: String, password: String) { - trackPreferences.setCredentials(this, username, password) - } + fun saveCredentials(username: String, password: String) // TODO: move this to an interactor, and update all trackers based on common data - 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) + suspend fun register(item: Track, mangaId: Long) - var track = item.toDomainTrack(idRequired = false) ?: return@withIOContext + suspend fun setRemoteStatus(track: Track, status: Int) - insertTrack.await(track) + suspend fun setRemoteLastChapterRead(track: Track, chapterNumber: Int) - // 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 + suspend fun setRemoteScore(track: Track, scoreString: String) - if (latestLocalReadChapterNumber > track.lastChapterRead) { - track = track.copy( - lastChapterRead = latestLocalReadChapterNumber, - ) - setRemoteLastChapterRead(track.toDbTrack(), latestLocalReadChapterNumber.toInt()) - } + suspend fun setRemoteStartDate(track: Track, epochMillis: Long) - 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@Tracker) - } - } catch (e: Throwable) { - withUIContext { Injekt.get().toast(e.message) } - } - } - - suspend fun setRemoteStatus(track: Track, status: Int) { - track.status = status - if (track.status == getCompletionStatus() && track.total_chapters != 0) { - track.last_chapter_read = track.total_chapters.toFloat() - } - withIOContext { updateRemote(track) } - } - - suspend fun setRemoteLastChapterRead(track: Track, chapterNumber: Int) { - if (track.last_chapter_read == 0f && track.last_chapter_read < chapterNumber && track.status != getRereadingStatus()) { - track.status = getReadingStatus() - } - track.last_chapter_read = chapterNumber.toFloat() - if (track.total_chapters != 0 && track.last_chapter_read.toInt() == track.total_chapters) { - track.status = getCompletionStatus() - track.finished_reading_date = System.currentTimeMillis() - } - withIOContext { updateRemote(track) } - } - - suspend fun setRemoteScore(track: Track, scoreString: String) { - track.score = indexToScore(getScoreList().indexOf(scoreString)) - withIOContext { updateRemote(track) } - } - - suspend fun setRemoteStartDate(track: Track, epochMillis: Long) { - track.started_reading_date = epochMillis - withIOContext { updateRemote(track) } - } - - suspend fun setRemoteFinishDate(track: Track, epochMillis: Long) { - track.finished_reading_date = epochMillis - withIOContext { 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) } - } - } - } + suspend fun setRemoteFinishDate(track: Track, epochMillis: Long) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt index 3ecf9119d..19227efea 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt @@ -4,15 +4,15 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track +import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.DeletableTracker -import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy import tachiyomi.domain.track.model.Track as DomainTrack -class Anilist(id: Long) : Tracker(id, "AniList"), DeletableTracker { +class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker { companion object { const val READING = 1 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt index 71aff2f2a..ca4ddbc66 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt @@ -4,13 +4,13 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.Tracker +import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy -class Bangumi(id: Long) : Tracker(id, "Bangumi") { +class Bangumi(id: Long) : BaseTracker(id, "Bangumi") { private val json: Json by injectLazy() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt index cb6e52e68..e9de55925 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt @@ -4,8 +4,8 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track +import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.EnhancedTracker -import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.Source @@ -16,7 +16,7 @@ import uy.kohesive.injekt.injectLazy import java.security.MessageDigest import tachiyomi.domain.track.model.Track as DomainTrack -class Kavita(id: Long) : Tracker(id, "Kavita"), EnhancedTracker { +class Kavita(id: Long) : BaseTracker(id, "Kavita"), EnhancedTracker { companion object { const val UNREAD = 1 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt index a2764c685..7c1fd34ff 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt @@ -4,15 +4,15 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track +import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.DeletableTracker -import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy import java.text.DecimalFormat -class Kitsu(id: Long) : Tracker(id, "Kitsu"), DeletableTracker { +class Kitsu(id: Long) : BaseTracker(id, "Kitsu"), DeletableTracker { companion object { const val READING = 1 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt index 450e502be..a2071c785 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt @@ -4,8 +4,8 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track +import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.EnhancedTracker -import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.source.Source import okhttp3.Dns @@ -13,7 +13,7 @@ import okhttp3.OkHttpClient import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.track.model.Track as DomainTrack -class Komga(id: Long) : Tracker(id, "Komga"), EnhancedTracker { +class Komga(id: Long) : BaseTracker(id, "Komga"), EnhancedTracker { companion object { const val UNREAD = 1 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt index 417f6acb8..14095f420 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt @@ -4,13 +4,13 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track +import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.DeletableTracker -import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch -class MangaUpdates(id: Long) : Tracker(id, "MangaUpdates"), DeletableTracker { +class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker { companion object { const val READING_LIST = 0 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt index cd0d1eb1b..d7141099a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt @@ -4,14 +4,14 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track +import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.DeletableTracker -import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy -class MyAnimeList(id: Long) : Tracker(id, "MyAnimeList"), DeletableTracker { +class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker { companion object { const val READING = 1 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt index 312c9acbd..2f39a9504 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt @@ -4,14 +4,14 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track +import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.DeletableTracker -import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy -class Shikimori(id: Long) : Tracker(id, "Shikimori"), DeletableTracker { +class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker { companion object { const val READING = 1 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 2c7fd67c4..6beca3851 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt @@ -4,14 +4,14 @@ import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track +import eu.kanade.tachiyomi.data.track.BaseTracker import eu.kanade.tachiyomi.data.track.EnhancedTracker -import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.source.Source import tachiyomi.domain.manga.model.Manga as DomainManga import tachiyomi.domain.track.model.Track as DomainTrack -class Suwayomi(id: Long) : Tracker(id, "Suwayomi"), EnhancedTracker { +class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker { val api by lazy { SuwayomiApi(id) } From 19965e0bdbe0ce3717451d402b7cac3a5a6ed6b2 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 21 Oct 2023 18:09:21 -0400 Subject: [PATCH 28/37] Update jsoup --- 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 7f3b34b54..62575a18e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,7 +25,7 @@ conscrypt-android = "org.conscrypt:conscrypt-android:2.5.2" quickjs-android = "app.cash.quickjs:quickjs-android:0.9.2" -jsoup = "org.jsoup:jsoup:1.16.1" +jsoup = "org.jsoup:jsoup:1.16.2" disklrucache = "com.jakewharton:disklrucache:2.0.2" unifile = "com.github.tachiyomiorg:unifile:17bec43" From 8e4cedf1735f80c604f971b0a03bf72b040cdade Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 21 Oct 2023 18:09:30 -0400 Subject: [PATCH 29/37] Update Compose --- .../eu/kanade/presentation/browse/BrowseSourceScreen.kt | 3 ++- .../kanade/presentation/browse/ExtensionDetailsScreen.kt | 4 ++-- .../eu/kanade/presentation/browse/ExtensionsScreen.kt | 5 ++++- .../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 | 3 ++- .../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/SettingsSearchScreen.kt | 5 ++++- .../more/settings/screen/SettingsTrackingScreen.kt | 3 ++- .../java/eu/kanade/presentation/track/TrackerSearch.kt | 3 ++- .../kanade/presentation/webview/WebViewScreenContent.kt | 8 +++++--- .../tachiyomi/ui/browse/migration/search/MigrateDialog.kt | 2 -- .../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 ++-- 27 files changed, 60 insertions(+), 46 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 833e4bf79..17943f8b2 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt @@ -4,6 +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 @@ -79,7 +80,7 @@ fun BrowseSourceContent( listOf( EmptyScreenAction( stringResId = R.string.local_source_help_guide, - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.Outlined.HelpOutline, onClick = onLocalSourceHelpClick, ), ) 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 b319f9fdc..715e93b52 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.outlined.HelpOutline +import androidx.compose.material.icons.automirrored.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.Outlined.HelpOutline, + icon = Icons.AutoMirrored.Outlined.HelpOutline, onClick = onClickReadme, ), ) diff --git a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt index fab831da7..28069f974 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt @@ -244,7 +244,10 @@ private fun ExtensionItem( ) } - val padding by animateDpAsState(targetValue = if (idle) 0.dp else 8.dp) + val padding by animateDpAsState( + targetValue = if (idle) 0.dp else 8.dp, + label = "iconPadding", + ) ExtensionIcon( extension = extension, modifier = Modifier 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..4afd8c9a2 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.filled.ViewList +import androidx.compose.material.icons.automirrored.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.Filled.ViewList else Icons.Filled.ViewModule, + icon = if (displayMode == LibraryDisplayMode.List) Icons.AutoMirrored.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 1270c011b..4661c304c 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,6 +11,7 @@ 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 @@ -54,7 +55,7 @@ fun GlobalSearchResultItem( Text(text = subtitle) } IconButton(onClick = onClick) { - Icon(imageVector = Icons.Outlined.ArrowForward, contentDescription = null) + Icon(imageVector = Icons.AutoMirrored.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 6f108abba..965894af8 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 { - ScrollableTabRow( + PrimaryScrollableTabRow( 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 02444a16f..ce9fb64bf 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 @@ -140,6 +140,7 @@ private fun DownloadingIndicator( val animatedProgress by animateFloatAsState( targetValue = downloadProgress / 100f, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, + label = "progress", ) arrowColor = if (animatedProgress < 0.5f) { strokeColor @@ -147,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 fa98e176b..6f31d5a1f 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,6 +23,7 @@ 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 @@ -258,7 +259,7 @@ fun LibraryBottomActionMenu( ) { Button( title = stringResource(R.string.action_move_category), - icon = Icons.Outlined.Label, + icon = Icons.AutoMirrored.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 5ef863c51..5a685ccaf 100644 --- a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt @@ -9,6 +9,8 @@ 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 @@ -128,7 +130,7 @@ fun MoreScreen( item { TextPreferenceWidget( title = stringResource(R.string.categories), - icon = Icons.Outlined.Label, + icon = Icons.AutoMirrored.Outlined.Label, onPreferenceClick = onClickCategories, ) } @@ -166,7 +168,7 @@ fun MoreScreen( item { TextPreferenceWidget( title = stringResource(R.string.label_help), - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.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 5e1c4d7ce..c1480a965 100644 --- a/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/NewUpdateScreen.kt @@ -5,6 +5,7 @@ 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 @@ -60,7 +61,7 @@ fun NewUpdateScreen( ) { Text(text = stringResource(R.string.update_check_open)) Spacer(modifier = Modifier.width(MaterialTheme.padding.tiny)) - Icon(imageVector = Icons.Default.OpenInNew, contentDescription = null) + Icon(imageVector = Icons.AutoMirrored.Outlined.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 5f9c4e9b5..93e33b28b 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,6 +9,7 @@ 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 @@ -186,7 +187,7 @@ object SettingsMainScreen : Screen() { Item( titleRes = R.string.pref_category_reader, subtitleRes = R.string.pref_reader_summary, - icon = Icons.Outlined.ChromeReaderMode, + icon = Icons.AutoMirrored.Outlined.ChromeReaderMode, screen = SettingsReaderScreen, ), Item( 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 aa25602e9..420722ccc 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 @@ -211,7 +211,10 @@ private fun SearchResult( .toList() } - Crossfade(targetState = result) { + Crossfade( + targetState = result, + label = "results", + ) { when { it == null -> {} it.isEmpty() -> { 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 655d79cc2..eebcaa22c 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,6 +9,7 @@ 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 @@ -72,7 +73,7 @@ object SettingsTrackingScreen : SearchableSettings { val uriHandler = LocalUriHandler.current IconButton(onClick = { uriHandler.openUri("https://tachiyomi.org/docs/guides/tracking") }) { Icon( - imageVector = Icons.Outlined.HelpOutline, + imageVector = Icons.AutoMirrored.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 c2b951453..8781faaa0 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt @@ -28,6 +28,7 @@ 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 @@ -94,7 +95,7 @@ fun TrackerSearch( navigationIcon = { IconButton(onClick = onDismissRequest) { Icon( - imageVector = Icons.Default.ArrowBack, + imageVector = Icons.AutoMirrored.Outlined.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 04133bc49..354fd2e29 100644 --- a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt +++ b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt @@ -11,6 +11,8 @@ 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 @@ -119,7 +121,7 @@ fun WebViewScreenContent( listOf( AppBar.Action( title = stringResource(R.string.action_webview_back), - icon = Icons.Outlined.ArrowBack, + icon = Icons.AutoMirrored.Outlined.ArrowBack, onClick = { if (navigator.canGoBack) { navigator.navigateBack() @@ -129,7 +131,7 @@ fun WebViewScreenContent( ), AppBar.Action( title = stringResource(R.string.action_webview_forward), - icon = Icons.Outlined.ArrowForward, + icon = Icons.AutoMirrored.Outlined.ArrowForward, onClick = { if (navigator.canGoForward) { navigator.navigateForward() @@ -180,7 +182,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/search/MigrateDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt index 386e8dd80..26bad6a5f 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 @@ -19,7 +19,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.toMutableStateList 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 @@ -65,7 +64,6 @@ internal fun MigrateDialog( onClickTitle: () -> Unit, onPopScreen: () -> Unit, ) { - val context = LocalContext.current val scope = rememberCoroutineScope() val state by screenModel.state.collectAsState() 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 fe53ccfad..8794c9078 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,6 +1,7 @@ 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 @@ -29,7 +30,7 @@ fun Screen.migrateSourceTab(): TabContent { actions = listOf( AppBar.Action( title = stringResource(R.string.migration_help_guide), - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.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 dcbb4536f..0fc7f3576 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,6 +10,7 @@ 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 @@ -185,7 +186,7 @@ object DownloadQueueScreen : Screen() { listOf( AppBar.Action( title = stringResource(R.string.action_sort), - icon = Icons.Outlined.Sort, + icon = Icons.AutoMirrored.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 5469a11a8..beab688e2 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,6 +6,7 @@ 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 @@ -157,7 +158,7 @@ object LibraryTab : Tab { actions = listOf( EmptyScreenAction( stringResId = R.string.getting_started_guide, - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.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 26f0809d0..ad2e6e603 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,7 +1,7 @@ [versions] compiler = "1.5.3" -compose-bom = "2023.09.00-alpha02" -accompanist = "0.33.1-alpha" +compose-bom = "2023.11.00-alpha02" +accompanist = "0.33.2-alpha" [libraries] activity = "androidx.activity:activity-compose:1.8.0" From 15423bfc8476179dff20ed49e5aa92a5387061ff Mon Sep 17 00:00:00 2001 From: Caleb Morris Date: Sat, 21 Oct 2023 18:42:09 -0700 Subject: [PATCH 30/37] Changed data-mappers to use function format (#10045) The lambda-format was really confusing to read and keep which anonymous data item was corresponding to which field. Now it's directly inspectable in the IDE --- .../tachiyomi/data/category/CategoryMapper.kt | 12 - .../data/category/CategoryRepositoryImpl.kt | 24 +- .../tachiyomi/data/chapter/ChapterMapper.kt | 36 --- .../data/chapter/ChapterRepositoryImpl.kt | 40 ++- .../tachiyomi/data/history/HistoryMapper.kt | 38 +-- .../data/history/HistoryRepositoryImpl.kt | 6 +- .../java/tachiyomi/data/manga/MangaMapper.kt | 228 +++++++++--------- .../data/manga/MangaRepositoryImpl.kt | 18 +- .../tachiyomi/data/source/SourceMapper.kt | 18 -- .../data/source/SourceRepositoryImpl.kt | 31 ++- .../data/source/StubSourceRepositoryImpl.kt | 10 +- .../java/tachiyomi/data/track/TrackMapper.kt | 36 --- .../data/track/TrackRepositoryImpl.kt | 38 ++- .../tachiyomi/data/updates/UpdatesMapper.kt | 42 ---- .../data/updates/UpdatesRepositoryImpl.kt | 42 +++- 15 files changed, 300 insertions(+), 319 deletions(-) delete mode 100644 data/src/main/java/tachiyomi/data/category/CategoryMapper.kt delete mode 100644 data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt delete mode 100644 data/src/main/java/tachiyomi/data/source/SourceMapper.kt delete mode 100644 data/src/main/java/tachiyomi/data/track/TrackMapper.kt delete mode 100644 data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt diff --git a/data/src/main/java/tachiyomi/data/category/CategoryMapper.kt b/data/src/main/java/tachiyomi/data/category/CategoryMapper.kt deleted file mode 100644 index 37f18ae80..000000000 --- a/data/src/main/java/tachiyomi/data/category/CategoryMapper.kt +++ /dev/null @@ -1,12 +0,0 @@ -package tachiyomi.data.category - -import tachiyomi.domain.category.model.Category - -val categoryMapper: (Long, String, Long, Long) -> Category = { id, name, order, flags -> - Category( - id = id, - name = name, - order = order, - flags = flags, - ) -} diff --git a/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt index 75cfbf7d1..bf379978e 100644 --- a/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt @@ -12,26 +12,26 @@ class CategoryRepositoryImpl( ) : CategoryRepository { override suspend fun get(id: Long): Category? { - return handler.awaitOneOrNull { categoriesQueries.getCategory(id, categoryMapper) } + return handler.awaitOneOrNull { categoriesQueries.getCategory(id, ::mapCategory) } } override suspend fun getAll(): List { - return handler.awaitList { categoriesQueries.getCategories(categoryMapper) } + return handler.awaitList { categoriesQueries.getCategories(::mapCategory) } } override fun getAllAsFlow(): Flow> { - return handler.subscribeToList { categoriesQueries.getCategories(categoryMapper) } + return handler.subscribeToList { categoriesQueries.getCategories(::mapCategory) } } override suspend fun getCategoriesByMangaId(mangaId: Long): List { return handler.awaitList { - categoriesQueries.getCategoriesByMangaId(mangaId, categoryMapper) + categoriesQueries.getCategoriesByMangaId(mangaId, ::mapCategory) } } override fun getCategoriesByMangaIdAsFlow(mangaId: Long): Flow> { return handler.subscribeToList { - categoriesQueries.getCategoriesByMangaId(mangaId, categoryMapper) + categoriesQueries.getCategoriesByMangaId(mangaId, ::mapCategory) } } @@ -81,4 +81,18 @@ class CategoryRepositoryImpl( ) } } + + private fun mapCategory( + id: Long, + name: String, + order: Long, + flags: Long, + ): Category { + return Category( + id = id, + name = name, + order = order, + flags = flags, + ) + } } diff --git a/data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt b/data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt deleted file mode 100644 index c8243682f..000000000 --- a/data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt +++ /dev/null @@ -1,36 +0,0 @@ -package tachiyomi.data.chapter - -import tachiyomi.domain.chapter.model.Chapter - -val chapterMapper: ( - Long, - Long, - String, - String, - String?, - Boolean, - Boolean, - Long, - Double, - Long, - Long, - Long, - Long, -) -> Chapter = - { id, mangaId, url, name, scanlator, read, bookmark, lastPageRead, chapterNumber, sourceOrder, dateFetch, dateUpload, lastModifiedAt -> - Chapter( - id = id, - mangaId = mangaId, - read = read, - bookmark = bookmark, - lastPageRead = lastPageRead, - dateFetch = dateFetch, - sourceOrder = sourceOrder, - url = url, - name = name, - dateUpload = dateUpload, - chapterNumber = chapterNumber, - scanlator = scanlator, - lastModifiedAt = lastModifiedAt, - ) - } diff --git a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt index 594a592ac..1249c8967 100644 --- a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt @@ -77,27 +77,27 @@ class ChapterRepositoryImpl( } override suspend fun getChapterByMangaId(mangaId: Long): List { - return handler.awaitList { chaptersQueries.getChaptersByMangaId(mangaId, chapterMapper) } + return handler.awaitList { chaptersQueries.getChaptersByMangaId(mangaId, ::mapChapter) } } override suspend fun getBookmarkedChaptersByMangaId(mangaId: Long): List { return handler.awaitList { chaptersQueries.getBookmarkedChaptersByMangaId( mangaId, - chapterMapper, + ::mapChapter, ) } } override suspend fun getChapterById(id: Long): Chapter? { - return handler.awaitOneOrNull { chaptersQueries.getChapterById(id, chapterMapper) } + return handler.awaitOneOrNull { chaptersQueries.getChapterById(id, ::mapChapter) } } override suspend fun getChapterByMangaIdAsFlow(mangaId: Long): Flow> { return handler.subscribeToList { chaptersQueries.getChaptersByMangaId( mangaId, - chapterMapper, + ::mapChapter, ) } } @@ -107,8 +107,38 @@ class ChapterRepositoryImpl( chaptersQueries.getChapterByUrlAndMangaId( url, mangaId, - chapterMapper, + ::mapChapter, ) } } + + private fun mapChapter( + id: Long, + mangaId: Long, + url: String, + name: String, + scanlator: String?, + read: Boolean, + bookmark: Boolean, + lastPageRead: Long, + chapterNumber: Double, + sourceOrder: Long, + dateFetch: Long, + dateUpload: Long, + lastModifiedAt: Long, + ): Chapter = Chapter( + id = id, + mangaId = mangaId, + read = read, + bookmark = bookmark, + lastPageRead = lastPageRead, + dateFetch = dateFetch, + sourceOrder = sourceOrder, + url = url, + name = name, + dateUpload = dateUpload, + chapterNumber = chapterNumber, + scanlator = scanlator, + lastModifiedAt = lastModifiedAt, + ) } diff --git a/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt b/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt index 134a1c91c..709c5800d 100644 --- a/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt +++ b/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt @@ -5,30 +5,32 @@ import tachiyomi.domain.history.model.HistoryWithRelations import tachiyomi.domain.manga.model.MangaCover import java.util.Date -val historyMapper: (Long, Long, Date?, Long) -> History = { id, chapterId, readAt, readDuration -> - History( +object HistoryMapper { + fun mapHistory( + id: Long, + chapterId: Long, + readAt: Date?, + readDuration: Long, + ): History = History( id = id, chapterId = chapterId, readAt = readAt, readDuration = readDuration, ) -} -val historyWithRelationsMapper: ( - Long, - Long, - Long, - String, - String?, - Long, - Boolean, - Long, - Double, - Date?, - Long, -) -> HistoryWithRelations = { - historyId, mangaId, chapterId, title, thumbnailUrl, sourceId, isFavorite, coverLastModified, chapterNumber, readAt, readDuration -> - HistoryWithRelations( + fun mapHistoryWithRelations( + historyId: Long, + mangaId: Long, + chapterId: Long, + title: String, + thumbnailUrl: String?, + sourceId: Long, + isFavorite: Boolean, + coverLastModified: Long, + chapterNumber: Double, + readAt: Date?, + readDuration: Long, + ): HistoryWithRelations = HistoryWithRelations( id = historyId, chapterId = chapterId, mangaId = mangaId, diff --git a/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt index 7f349afc2..103a0995b 100644 --- a/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt @@ -15,13 +15,13 @@ class HistoryRepositoryImpl( override fun getHistory(query: String): Flow> { return handler.subscribeToList { - historyViewQueries.history(query, historyWithRelationsMapper) + historyViewQueries.history(query, HistoryMapper::mapHistoryWithRelations) } } override suspend fun getLastHistory(): HistoryWithRelations? { return handler.awaitOneOrNull { - historyViewQueries.getLatestHistory(historyWithRelationsMapper) + historyViewQueries.getLatestHistory(HistoryMapper::mapHistoryWithRelations) } } @@ -30,7 +30,7 @@ class HistoryRepositoryImpl( } override suspend fun getHistoryByMangaId(mangaId: Long): List { - return handler.awaitList { historyQueries.getHistoryByMangaId(mangaId, historyMapper) } + return handler.awaitList { historyQueries.getHistoryByMangaId(mangaId, HistoryMapper::mapHistory) } } override suspend fun resetHistory(historyId: Long) { diff --git a/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt b/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt index 43bb1ed0c..d9937b285 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt @@ -4,120 +4,116 @@ import eu.kanade.tachiyomi.source.model.UpdateStrategy import tachiyomi.domain.library.model.LibraryManga import tachiyomi.domain.manga.model.Manga -val mangaMapper: ( - Long, - Long, - String, - String?, - String?, - String?, - List?, - String, - Long, - String?, - Boolean, - Long?, - Long?, - Boolean, - Long, - Long, - Long, - Long, - UpdateStrategy, - Long, - Long, - Long?, -) -> Manga = - { id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt -> - Manga( - id = id, - source = source, - favorite = favorite, - lastUpdate = lastUpdate ?: 0, - nextUpdate = nextUpdate ?: 0, - fetchInterval = calculateInterval.toInt(), - dateAdded = dateAdded, - viewerFlags = viewerFlags, - chapterFlags = chapterFlags, - coverLastModified = coverLastModified, - url = url, - title = title, - artist = artist, - author = author, - description = description, - genre = genre, - status = status, - thumbnailUrl = thumbnailUrl, - updateStrategy = updateStrategy, - initialized = initialized, - lastModifiedAt = lastModifiedAt, - favoriteModifiedAt = favoriteModifiedAt, - ) - } +object MangaMapper { + fun mapManga( + id: Long, + source: Long, + url: String, + artist: String?, + author: String?, + description: String?, + genre: List?, + title: String, + status: Long, + thumbnailUrl: String?, + favorite: Boolean, + lastUpdate: Long?, + nextUpdate: Long?, + initialized: Boolean, + viewerFlags: Long, + chapterFlags: Long, + coverLastModified: Long, + dateAdded: Long, + updateStrategy: UpdateStrategy, + calculateInterval: Long, + lastModifiedAt: Long, + favoriteModifiedAt: Long?, + ): Manga = Manga( + id = id, + source = source, + favorite = favorite, + lastUpdate = lastUpdate ?: 0, + nextUpdate = nextUpdate ?: 0, + fetchInterval = calculateInterval.toInt(), + dateAdded = dateAdded, + viewerFlags = viewerFlags, + chapterFlags = chapterFlags, + coverLastModified = coverLastModified, + url = url, + title = title, + artist = artist, + author = author, + description = description, + genre = genre, + status = status, + thumbnailUrl = thumbnailUrl, + updateStrategy = updateStrategy, + initialized = initialized, + lastModifiedAt = lastModifiedAt, + favoriteModifiedAt = favoriteModifiedAt, + ) -val libraryManga: ( - Long, - Long, - String, - String?, - String?, - String?, - List?, - String, - Long, - String?, - Boolean, - Long?, - Long?, - Boolean, - Long, - Long, - Long, - Long, - UpdateStrategy, - Long, - Long, - Long?, - Long, - Double, - Long, - Long, - Long, - Double, - Long, -) -> LibraryManga = - { id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt, totalCount, readCount, latestUpload, chapterFetchedAt, lastRead, bookmarkCount, category -> - LibraryManga( - manga = mangaMapper( - id, - source, - url, - artist, - author, - description, - genre, - title, - status, - thumbnailUrl, - favorite, - lastUpdate, - nextUpdate, - initialized, - viewerFlags, - chapterFlags, - coverLastModified, - dateAdded, - updateStrategy, - calculateInterval, - lastModifiedAt, - favoriteModifiedAt, - ), - category = category, - totalChapters = totalCount, - readCount = readCount.toLong(), - bookmarkCount = bookmarkCount.toLong(), - latestUpload = latestUpload, - chapterFetchedAt = chapterFetchedAt, - lastRead = lastRead, - ) - } + fun mapLibraryManga( + id: Long, + source: Long, + url: String, + artist: String?, + author: String?, + description: String?, + genre: List?, + title: String, + status: Long, + thumbnailUrl: String?, + favorite: Boolean, + lastUpdate: Long?, + nextUpdate: Long?, + initialized: Boolean, + viewerFlags: Long, + chapterFlags: Long, + coverLastModified: Long, + dateAdded: Long, + updateStrategy: UpdateStrategy, + calculateInterval: Long, + lastModifiedAt: Long, + favoriteModifiedAt: Long?, + totalCount: Long, + readCount: Double, + latestUpload: Long, + chapterFetchedAt: Long, + lastRead: Long, + bookmarkCount: Double, + category: Long, + ): LibraryManga = LibraryManga( + manga = mapManga( + id, + source, + url, + artist, + author, + description, + genre, + title, + status, + thumbnailUrl, + favorite, + lastUpdate, + nextUpdate, + initialized, + viewerFlags, + chapterFlags, + coverLastModified, + dateAdded, + updateStrategy, + calculateInterval, + lastModifiedAt, + favoriteModifiedAt, + ), + category = category, + totalChapters = totalCount, + readCount = readCount.toLong(), + bookmarkCount = bookmarkCount.toLong(), + latestUpload = latestUpload, + chapterFetchedAt = chapterFetchedAt, + lastRead = lastRead, + ) +} diff --git a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt index 39bbcb99f..5d8364f31 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt @@ -16,11 +16,11 @@ class MangaRepositoryImpl( ) : MangaRepository { override suspend fun getMangaById(id: Long): Manga { - return handler.awaitOne { mangasQueries.getMangaById(id, mangaMapper) } + return handler.awaitOne { mangasQueries.getMangaById(id, MangaMapper::mapManga) } } override suspend fun getMangaByIdAsFlow(id: Long): Flow { - return handler.subscribeToOne { mangasQueries.getMangaById(id, mangaMapper) } + return handler.subscribeToOne { mangasQueries.getMangaById(id, MangaMapper::mapManga) } } override suspend fun getMangaByUrlAndSourceId(url: String, sourceId: Long): Manga? { @@ -28,7 +28,7 @@ class MangaRepositoryImpl( mangasQueries.getMangaByUrlAndSource( url, sourceId, - mangaMapper, + MangaMapper::mapManga, ) } } @@ -38,30 +38,30 @@ class MangaRepositoryImpl( mangasQueries.getMangaByUrlAndSource( url, sourceId, - mangaMapper, + MangaMapper::mapManga, ) } } override suspend fun getFavorites(): List { - return handler.awaitList { mangasQueries.getFavorites(mangaMapper) } + return handler.awaitList { mangasQueries.getFavorites(MangaMapper::mapManga) } } override suspend fun getLibraryManga(): List { - return handler.awaitList { libraryViewQueries.library(libraryManga) } + return handler.awaitList { libraryViewQueries.library(MangaMapper::mapLibraryManga) } } override fun getLibraryMangaAsFlow(): Flow> { - return handler.subscribeToList { libraryViewQueries.library(libraryManga) } + return handler.subscribeToList { libraryViewQueries.library(MangaMapper::mapLibraryManga) } } override fun getFavoritesBySourceId(sourceId: Long): Flow> { - return handler.subscribeToList { mangasQueries.getFavoriteBySourceId(sourceId, mangaMapper) } + return handler.subscribeToList { mangasQueries.getFavoriteBySourceId(sourceId, MangaMapper::mapManga) } } override suspend fun getDuplicateLibraryManga(id: Long, title: String): List { return handler.awaitList { - mangasQueries.getDuplicateLibraryManga(title, id, mangaMapper) + mangasQueries.getDuplicateLibraryManga(title, id, MangaMapper::mapManga) } } diff --git a/data/src/main/java/tachiyomi/data/source/SourceMapper.kt b/data/src/main/java/tachiyomi/data/source/SourceMapper.kt deleted file mode 100644 index 8b598152e..000000000 --- a/data/src/main/java/tachiyomi/data/source/SourceMapper.kt +++ /dev/null @@ -1,18 +0,0 @@ -package tachiyomi.data.source - -import tachiyomi.domain.source.model.Source -import tachiyomi.domain.source.model.StubSource - -val sourceMapper: (eu.kanade.tachiyomi.source.Source) -> Source = { source -> - Source( - id = source.id, - lang = source.lang, - name = source.name, - supportsLatest = false, - isStub = false, - ) -} - -val sourceDataMapper: (Long, String, String) -> StubSource = { id, lang, name -> - StubSource(id = id, lang = lang, name = name) -} diff --git a/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt index c5f1ee608..e8cf8f43c 100644 --- a/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt @@ -1,48 +1,50 @@ package tachiyomi.data.source import eu.kanade.tachiyomi.source.CatalogueSource +import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.online.HttpSource import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import tachiyomi.data.DatabaseHandler -import tachiyomi.domain.source.model.Source import tachiyomi.domain.source.model.SourceWithCount import tachiyomi.domain.source.model.StubSource import tachiyomi.domain.source.repository.SourcePagingSourceType import tachiyomi.domain.source.repository.SourceRepository import tachiyomi.domain.source.service.SourceManager +import tachiyomi.domain.source.model.Source as DomainSource class SourceRepositoryImpl( private val sourceManager: SourceManager, private val handler: DatabaseHandler, ) : SourceRepository { - override fun getSources(): Flow> { + override fun getSources(): Flow> { return sourceManager.catalogueSources.map { sources -> sources.map { - sourceMapper(it).copy( + mapSourceToDomainSource(it).copy( supportsLatest = it.supportsLatest, ) } } } - override fun getOnlineSources(): Flow> { + override fun getOnlineSources(): Flow> { return sourceManager.catalogueSources.map { sources -> sources .filterIsInstance() - .map(sourceMapper) + .map(::mapSourceToDomainSource) } } - override fun getSourcesWithFavoriteCount(): Flow>> { - val sourceIdWithFavoriteCount = handler.subscribeToList { mangasQueries.getSourceIdWithFavoriteCount() } + override fun getSourcesWithFavoriteCount(): Flow>> { + val sourceIdWithFavoriteCount = + handler.subscribeToList { mangasQueries.getSourceIdWithFavoriteCount() } return sourceIdWithFavoriteCount.map { sourceIdsWithCount -> sourceIdsWithCount .map { (sourceId, count) -> val source = sourceManager.getOrStub(sourceId) - val domainSource = sourceMapper(source).copy( + val domainSource = mapSourceToDomainSource(source).copy( isStub = source is StubSource, ) domainSource to count @@ -51,11 +53,12 @@ class SourceRepositoryImpl( } override fun getSourcesWithNonLibraryManga(): Flow> { - val sourceIdWithNonLibraryManga = handler.subscribeToList { mangasQueries.getSourceIdsWithNonLibraryManga() } + val sourceIdWithNonLibraryManga = + handler.subscribeToList { mangasQueries.getSourceIdsWithNonLibraryManga() } return sourceIdWithNonLibraryManga.map { sourceId -> sourceId.map { (sourceId, count) -> val source = sourceManager.getOrStub(sourceId) - val domainSource = sourceMapper(source).copy( + val domainSource = mapSourceToDomainSource(source).copy( isStub = source is StubSource, ) SourceWithCount(domainSource, count) @@ -81,4 +84,12 @@ class SourceRepositoryImpl( val source = sourceManager.get(sourceId) as CatalogueSource return SourceLatestPagingSource(source) } + + private fun mapSourceToDomainSource(source: Source): DomainSource = DomainSource( + id = source.id, + lang = source.lang, + name = source.name, + supportsLatest = false, + isStub = false, + ) } diff --git a/data/src/main/java/tachiyomi/data/source/StubSourceRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/source/StubSourceRepositoryImpl.kt index 9dd068139..157e1eb2f 100644 --- a/data/src/main/java/tachiyomi/data/source/StubSourceRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/source/StubSourceRepositoryImpl.kt @@ -10,14 +10,20 @@ class StubSourceRepositoryImpl( ) : StubSourceRepository { override fun subscribeAll(): Flow> { - return handler.subscribeToList { sourcesQueries.findAll(sourceDataMapper) } + return handler.subscribeToList { sourcesQueries.findAll(::mapStubSource) } } override suspend fun getStubSource(id: Long): StubSource? { - return handler.awaitOneOrNull { sourcesQueries.findOne(id, sourceDataMapper) } + return handler.awaitOneOrNull { sourcesQueries.findOne(id, ::mapStubSource) } } override suspend fun upsertStubSource(id: Long, lang: String, name: String) { handler.await { sourcesQueries.upsert(id, lang, name) } } + + private fun mapStubSource( + id: Long, + lang: String, + name: String, + ): StubSource = StubSource(id = id, lang = lang, name = name) } diff --git a/data/src/main/java/tachiyomi/data/track/TrackMapper.kt b/data/src/main/java/tachiyomi/data/track/TrackMapper.kt deleted file mode 100644 index a4a9714f6..000000000 --- a/data/src/main/java/tachiyomi/data/track/TrackMapper.kt +++ /dev/null @@ -1,36 +0,0 @@ -package tachiyomi.data.track - -import tachiyomi.domain.track.model.Track - -val trackMapper: ( - Long, - Long, - Long, - Long, - Long?, - String, - Double, - Long, - Long, - Double, - String, - Long, - Long, -) -> Track = - { id, mangaId, syncId, remoteId, libraryId, title, lastChapterRead, totalChapters, status, score, remoteUrl, startDate, finishDate -> - Track( - id = id, - mangaId = mangaId, - syncId = syncId, - remoteId = remoteId, - libraryId = libraryId, - title = title, - lastChapterRead = lastChapterRead, - totalChapters = totalChapters, - status = status, - score = score, - remoteUrl = remoteUrl, - startDate = startDate, - finishDate = finishDate, - ) - } diff --git a/data/src/main/java/tachiyomi/data/track/TrackRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/track/TrackRepositoryImpl.kt index 0643c5c30..1966a013b 100644 --- a/data/src/main/java/tachiyomi/data/track/TrackRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/track/TrackRepositoryImpl.kt @@ -10,24 +10,24 @@ class TrackRepositoryImpl( ) : TrackRepository { override suspend fun getTrackById(id: Long): Track? { - return handler.awaitOneOrNull { manga_syncQueries.getTrackById(id, trackMapper) } + return handler.awaitOneOrNull { manga_syncQueries.getTrackById(id, ::mapTrack) } } override suspend fun getTracksByMangaId(mangaId: Long): List { return handler.awaitList { - manga_syncQueries.getTracksByMangaId(mangaId, trackMapper) + manga_syncQueries.getTracksByMangaId(mangaId, ::mapTrack) } } override fun getTracksAsFlow(): Flow> { return handler.subscribeToList { - manga_syncQueries.getTracks(trackMapper) + manga_syncQueries.getTracks(::mapTrack) } } override fun getTracksByMangaIdAsFlow(mangaId: Long): Flow> { return handler.subscribeToList { - manga_syncQueries.getTracksByMangaId(mangaId, trackMapper) + manga_syncQueries.getTracksByMangaId(mangaId, ::mapTrack) } } @@ -68,4 +68,34 @@ class TrackRepositoryImpl( } } } + + private fun mapTrack( + id: Long, + mangaId: Long, + syncId: Long, + remoteId: Long, + libraryId: Long?, + title: String, + lastChapterRead: Double, + totalChapters: Long, + status: Long, + score: Double, + remoteUrl: String, + startDate: Long, + finishDate: Long, + ): Track = Track( + id = id, + mangaId = mangaId, + syncId = syncId, + remoteId = remoteId, + libraryId = libraryId, + title = title, + lastChapterRead = lastChapterRead, + totalChapters = totalChapters, + status = status, + score = score, + remoteUrl = remoteUrl, + startDate = startDate, + finishDate = finishDate, + ) } diff --git a/data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt b/data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt deleted file mode 100644 index 56e9743a9..000000000 --- a/data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt +++ /dev/null @@ -1,42 +0,0 @@ -package tachiyomi.data.updates - -import tachiyomi.domain.manga.model.MangaCover -import tachiyomi.domain.updates.model.UpdatesWithRelations - -val updateWithRelationMapper: ( - Long, - String, - Long, - String, - String?, - Boolean, - Boolean, - Long, - Long, - Boolean, - String?, - Long, - Long, - Long, -) -> UpdatesWithRelations = { - mangaId, mangaTitle, chapterId, chapterName, scanlator, read, bookmark, lastPageRead, sourceId, favorite, thumbnailUrl, coverLastModified, _, dateFetch -> - UpdatesWithRelations( - mangaId = mangaId, - mangaTitle = mangaTitle, - chapterId = chapterId, - chapterName = chapterName, - scanlator = scanlator, - read = read, - bookmark = bookmark, - lastPageRead = lastPageRead, - sourceId = sourceId, - dateFetch = dateFetch, - coverData = MangaCover( - mangaId = mangaId, - sourceId = sourceId, - isMangaFavorite = favorite, - url = thumbnailUrl, - lastModified = coverLastModified, - ), - ) -} diff --git a/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt index b50aee4be..0af6bcd50 100644 --- a/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt @@ -2,6 +2,7 @@ package tachiyomi.data.updates import kotlinx.coroutines.flow.Flow import tachiyomi.data.DatabaseHandler +import tachiyomi.domain.manga.model.MangaCover import tachiyomi.domain.updates.model.UpdatesWithRelations import tachiyomi.domain.updates.repository.UpdatesRepository @@ -19,14 +20,14 @@ class UpdatesRepositoryImpl( read = read, after = after, limit = limit, - mapper = updateWithRelationMapper, + mapper = ::mapUpdatesWithRelations, ) } } override fun subscribeAll(after: Long, limit: Long): Flow> { return databaseHandler.subscribeToList { - updatesViewQueries.getRecentUpdates(after, limit, updateWithRelationMapper) + updatesViewQueries.getRecentUpdates(after, limit, ::mapUpdatesWithRelations) } } @@ -40,8 +41,43 @@ class UpdatesRepositoryImpl( read = read, after = after, limit = limit, - mapper = updateWithRelationMapper, + mapper = ::mapUpdatesWithRelations, ) } } + + private fun mapUpdatesWithRelations( + mangaId: Long, + mangaTitle: String, + chapterId: Long, + chapterName: String, + scanlator: String?, + read: Boolean, + bookmark: Boolean, + lastPageRead: Long, + sourceId: Long, + favorite: Boolean, + thumbnailUrl: String?, + coverLastModified: Long, + dateUpload: Long, + dateFetch: Long, + ): UpdatesWithRelations = UpdatesWithRelations( + mangaId = mangaId, + mangaTitle = mangaTitle, + chapterId = chapterId, + chapterName = chapterName, + scanlator = scanlator, + read = read, + bookmark = bookmark, + lastPageRead = lastPageRead, + sourceId = sourceId, + dateFetch = dateFetch, + coverData = MangaCover( + mangaId = mangaId, + sourceId = sourceId, + isMangaFavorite = favorite, + url = thumbnailUrl, + lastModified = coverLastModified, + ), + ) } From f84868a2641578b7e07719d8f580e4668804fd50 Mon Sep 17 00:00:00 2001 From: Joshua Owolabi Date: Sun, 22 Oct 2023 02:44:43 +0100 Subject: [PATCH 31/37] Allow extensions to open manga or chapter by URL (#9996) * open manga and chapter using URL * removing unnnecessary logs * Resolving comments * Resolving comments --- .../java/eu/kanade/domain/DomainModule.kt | 4 ++ .../tachiyomi/ui/deeplink/DeepLinkScreen.kt | 25 ++++++--- .../ui/deeplink/DeepLinkScreenModel.kt | 54 +++++++++++++++++-- .../interactor/GetChapterByUrlAndMangaId.kt | 17 ++++++ .../interactor/GetMangaByUrlAndSourceId.kt | 12 +++++ .../tachiyomi/source/online/HttpSource.kt | 7 +++ .../source/online/ResolvableSource.kt | 19 ++++++- 7 files changed, 125 insertions(+), 13 deletions(-) create mode 100644 domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChapterByUrlAndMangaId.kt create mode 100644 domain/src/main/java/tachiyomi/domain/manga/interactor/GetMangaByUrlAndSourceId.kt diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 4da261de6..8559cd923 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -41,6 +41,7 @@ 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.SetMangaDefaultChapterFlags import tachiyomi.domain.chapter.interactor.ShouldUpdateDbChapter import tachiyomi.domain.chapter.interactor.UpdateChapter @@ -56,6 +57,7 @@ import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga import tachiyomi.domain.manga.interactor.GetFavorites import tachiyomi.domain.manga.interactor.GetLibraryManga import tachiyomi.domain.manga.interactor.GetManga +import tachiyomi.domain.manga.interactor.GetMangaByUrlAndSourceId import tachiyomi.domain.manga.interactor.GetMangaWithChapters import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.interactor.ResetViewerFlags @@ -99,6 +101,7 @@ class DomainModule : InjektModule { addFactory { GetFavorites(get()) } addFactory { GetLibraryManga(get()) } addFactory { GetMangaWithChapters(get(), get()) } + addFactory { GetMangaByUrlAndSourceId(get()) } addFactory { GetManga(get()) } addFactory { GetNextChapters(get(), get(), get()) } addFactory { ResetViewerFlags(get()) } @@ -126,6 +129,7 @@ class DomainModule : InjektModule { addSingletonFactory { ChapterRepositoryImpl(get()) } addFactory { GetChapter(get()) } addFactory { GetChapterByMangaId(get()) } + addFactory { GetChapterByUrlAndMangaId(get()) } addFactory { UpdateChapter(get()) } addFactory { SetReadStatus(get(), get(), get(), get()) } addFactory { ShouldUpdateDbChapter() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreen.kt index 4b7c989dc..87e75f46b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreen.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.Composable 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 cafe.adriel.voyager.core.model.rememberScreenModel import cafe.adriel.voyager.navigator.LocalNavigator @@ -14,6 +15,7 @@ import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen import eu.kanade.tachiyomi.ui.manga.MangaScreen +import eu.kanade.tachiyomi.ui.reader.ReaderActivity import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.screens.LoadingScreen @@ -23,6 +25,7 @@ class DeepLinkScreen( @Composable override fun Content() { + val context = LocalContext.current val navigator = LocalNavigator.currentOrThrow val screenModel = rememberScreenModel { @@ -46,12 +49,22 @@ class DeepLinkScreen( navigator.replace(GlobalSearchScreen(query)) } is DeepLinkScreenModel.State.Result -> { - navigator.replace( - MangaScreen( - (state as DeepLinkScreenModel.State.Result).manga.id, - true, - ), - ) + val resultState = state as DeepLinkScreenModel.State.Result + if (resultState.chapterId == null) { + navigator.replace( + MangaScreen( + resultState.manga.id, + true, + ), + ) + } else { + navigator.pop() + ReaderActivity.newIntent( + context, + resultState.manga.id, + resultState.chapterId, + ).also(context::startActivity) + } } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt index 4446c28a4..bd10f8a6c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt @@ -3,10 +3,20 @@ package eu.kanade.tachiyomi.ui.deeplink import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.coroutineScope +import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.manga.model.toDomainManga +import eu.kanade.domain.manga.model.toSManga +import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.ResolvableSource +import eu.kanade.tachiyomi.source.online.UriType import kotlinx.coroutines.flow.update import tachiyomi.core.util.lang.launchIO +import tachiyomi.domain.chapter.interactor.GetChapterByUrlAndMangaId +import tachiyomi.domain.chapter.model.Chapter +import tachiyomi.domain.manga.interactor.GetMangaByUrlAndSourceId +import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.Injekt @@ -15,25 +25,59 @@ import uy.kohesive.injekt.api.get class DeepLinkScreenModel( query: String = "", private val sourceManager: SourceManager = Injekt.get(), + private val networkToLocalManga: NetworkToLocalManga = Injekt.get(), + private val getChapterByUrlAndMangaId: GetChapterByUrlAndMangaId = Injekt.get(), + private val getMangaByUrlAndSourceId: GetMangaByUrlAndSourceId = Injekt.get(), + private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(), ) : StateScreenModel(State.Loading) { init { coroutineScope.launchIO { - val manga = sourceManager.getCatalogueSources() + val source = sourceManager.getCatalogueSources() .filterIsInstance() - .filter { it.canResolveUri(query) } - .firstNotNullOfOrNull { it.getManga(query)?.toDomainManga(it.id) } + .firstOrNull { it.getUriType(query) != UriType.Unknown } + + val manga = source?.getManga(query)?.let { + getMangaFromSManga(it, source.id) + } + + val chapter = if (source?.getUriType(query) == UriType.Chapter && manga != null) { + source.getChapter(query)?.let { getChapterFromSChapter(it, manga, source) } + } else { + null + } mutableState.update { if (manga == null) { State.NoResults } else { - State.Result(manga) + if (chapter == null) { + State.Result(manga) + } else { + State.Result(manga, chapter.id) + } } } } } + private suspend fun getChapterFromSChapter(sChapter: SChapter, manga: Manga, source: Source): Chapter? { + val localChapter = getChapterByUrlAndMangaId.await(sChapter.url, manga.id) + + return if (localChapter == null) { + val sourceChapters = source.getChapterList(manga.toSManga()) + val newChapters = syncChaptersWithSource.await(sourceChapters, manga, source, false) + newChapters.find { it.url == sChapter.url } + } else { + localChapter + } + } + + private suspend fun getMangaFromSManga(sManga: SManga, sourceId: Long): Manga { + return getMangaByUrlAndSourceId.awaitManga(sManga.url, sourceId) + ?: networkToLocalManga.await(sManga.toDomainManga(sourceId)) + } + sealed interface State { @Immutable data object Loading : State @@ -42,6 +86,6 @@ class DeepLinkScreenModel( data object NoResults : State @Immutable - data class Result(val manga: Manga) : State + data class Result(val manga: Manga, val chapterId: Long? = null) : State } } diff --git a/domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChapterByUrlAndMangaId.kt b/domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChapterByUrlAndMangaId.kt new file mode 100644 index 000000000..f0399d17f --- /dev/null +++ b/domain/src/main/java/tachiyomi/domain/chapter/interactor/GetChapterByUrlAndMangaId.kt @@ -0,0 +1,17 @@ +package tachiyomi.domain.chapter.interactor + +import tachiyomi.domain.chapter.model.Chapter +import tachiyomi.domain.chapter.repository.ChapterRepository + +class GetChapterByUrlAndMangaId( + private val chapterRepository: ChapterRepository, +) { + + suspend fun await(url: String, sourceId: Long): Chapter? { + return try { + chapterRepository.getChapterByUrlAndMangaId(url, sourceId) + } catch (e: Exception) { + null + } + } +} diff --git a/domain/src/main/java/tachiyomi/domain/manga/interactor/GetMangaByUrlAndSourceId.kt b/domain/src/main/java/tachiyomi/domain/manga/interactor/GetMangaByUrlAndSourceId.kt new file mode 100644 index 000000000..507000d82 --- /dev/null +++ b/domain/src/main/java/tachiyomi/domain/manga/interactor/GetMangaByUrlAndSourceId.kt @@ -0,0 +1,12 @@ +package tachiyomi.domain.manga.interactor + +import tachiyomi.domain.manga.model.Manga +import tachiyomi.domain.manga.repository.MangaRepository + +class GetMangaByUrlAndSourceId( + private val mangaRepository: MangaRepository, +) { + suspend fun awaitManga(url: String, sourceId: Long): Manga? { + return mangaRepository.getMangaByUrlAndSourceId(url, sourceId) + } +} diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt index 957febceb..7450a60bf 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt @@ -289,6 +289,13 @@ abstract class HttpSource : CatalogueSource { */ protected abstract fun chapterListParse(response: Response): List + /** + * Parses the response from the site and returns a SChapter Object. + * + * @param response the response from the site. + */ + protected abstract fun chapterPageParse(response: Response): SChapter + /** * Get the list of pages a chapter has. Pages should be returned * in the expected order; the index is ignored. diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/ResolvableSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/ResolvableSource.kt index 6a00c2e55..5885844c8 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/ResolvableSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/ResolvableSource.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.source.online import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga /** @@ -11,11 +12,12 @@ import eu.kanade.tachiyomi.source.model.SManga interface ResolvableSource : Source { /** - * Whether this source may potentially handle the given URI. + * Returns the UriType of the uri input. + * Returns Unknown if unable to resolve the URI * * @since extensions-lib 1.5 */ - fun canResolveUri(uri: String): Boolean + fun getUriType(uri: String): UriType /** * Called if canHandleUri is true. Returns the corresponding SManga, if possible. @@ -23,4 +25,17 @@ interface ResolvableSource : Source { * @since extensions-lib 1.5 */ suspend fun getManga(uri: String): SManga? + + /** + * Called if canHandleUri is true. Returns the corresponding SChapter, if possible. + * + * @since extensions-lib 1.5 + */ + suspend fun getChapter(uri: String): SChapter? +} + +sealed interface UriType { + object Manga : UriType + object Chapter : UriType + object Unknown : UriType } From fcba2306e9d15aa4e00e67bde493fd7aa3f79d9f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 21 Oct 2023 21:44:54 -0400 Subject: [PATCH 32/37] Update dependency ch.acra:acra-http to v5.11.3 (#10046) 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 62575a18e..ffd9cabb4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -63,7 +63,7 @@ swipe = "me.saket.swipe:swipe:1.2.0" logcat = "com.squareup.logcat:logcat:0.1" -acra-http = "ch.acra:acra-http:5.11.2" +acra-http = "ch.acra:acra-http:5.11.3" firebase-analytics = "com.google.firebase:firebase-analytics-ktx:21.4.0" aboutLibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin", version.ref = "aboutlib_version" } From 732659847571359624ee48b17c3c268a5c7d7fb2 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 21 Oct 2023 21:50:53 -0400 Subject: [PATCH 33/37] Minor cleanup to ResolvableSource --- .../source/online/ResolvableSource.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/ResolvableSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/ResolvableSource.kt index 5885844c8..dd06ff301 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/ResolvableSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/ResolvableSource.kt @@ -5,29 +5,31 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga /** - * A source that may handle opening an SManga for a given URI. + * A source that may handle opening an SManga or SChapter for a given URI. * * @since extensions-lib 1.5 */ interface ResolvableSource : Source { /** - * Returns the UriType of the uri input. - * Returns Unknown if unable to resolve the URI + * Returns what the given URI may open. + * Returns [UriType.Unknown] if the source is not able to resolve the URI. * * @since extensions-lib 1.5 */ fun getUriType(uri: String): UriType /** - * Called if canHandleUri is true. Returns the corresponding SManga, if possible. + * Called if [getUriType] is [UriType.Manga]. + * Returns the corresponding SManga, if possible. * * @since extensions-lib 1.5 */ suspend fun getManga(uri: String): SManga? /** - * Called if canHandleUri is true. Returns the corresponding SChapter, if possible. + * Called if [getUriType] is [UriType.Chapter]. + * Returns the corresponding SChapter, if possible. * * @since extensions-lib 1.5 */ @@ -35,7 +37,7 @@ interface ResolvableSource : Source { } sealed interface UriType { - object Manga : UriType - object Chapter : UriType - object Unknown : UriType + data object Manga : UriType + data object Chapter : UriType + data object Unknown : UriType } From dcc3141080aca6cfe70b21c5c6ed34b2e343fa97 Mon Sep 17 00:00:00 2001 From: Gabriel Donadel Dall'Agnol Date: Sat, 21 Oct 2023 23:00:05 -0300 Subject: [PATCH 34/37] Fix README.md typo (#10047) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 911cef4b9..0beaf83ae 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Please make sure to read the full guidelines. Your issue may be closed without w * Include version (More → About → Version) * If not latest, try updating, it may have already been solved - * Preview version is equal to the number of commits as seen in the main page + * Preview version is equal to the number of commits as seen on the main page * Include steps to reproduce (if not obvious from description) * Include screenshot (if needed) * If it could be device-dependent, try reproducing on another device (if possible) From 6d1e520c6c5c3860bbd588677bb4a05ab06fe830 Mon Sep 17 00:00:00 2001 From: Caleb Morris Date: Sun, 22 Oct 2023 06:30:34 -0700 Subject: [PATCH 35/37] [dev QoL] Added AndroidStudio previews for [presentation.track] namespace (#10022) * Created DummyTracker for use in tests and presentation previews * Added previews for TrackerSearch * Added previews for TrackLogoIcon * Added preview for TrackInfoDialogSelector * Added previews for TrackInfoDialogHome --- .../presentation/track/TrackInfoDialogHome.kt | 14 +++ .../TrackInfoDialogHomePreviewProvider.kt | 81 ++++++++++++ .../track/TrackInfoDialogSelector.kt | 24 ++++ .../presentation/track/TrackerSearch.kt | 12 ++ .../track/TrackerSearchPreviewProvider.kt | 84 +++++++++++++ .../track/components/TrackLogoIcon.kt | 17 +++ .../TrackLogoIconPreviewProvider.kt | 20 +++ .../tachiyomi/dev/preview/DummyTracker.kt | 115 ++++++++++++++++++ 8 files changed, 367 insertions(+) create mode 100644 app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt create mode 100644 app/src/main/java/eu/kanade/presentation/track/TrackerSearchPreviewProvider.kt create mode 100644 app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt 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 bf7860147..d0b31ca06 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt @@ -44,14 +44,17 @@ 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.PreviewParameter import androidx.compose.ui.unit.dp import eu.kanade.domain.track.model.toDbTrack import eu.kanade.presentation.components.DropdownMenu +import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.presentation.track.components.TrackLogoIcon 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 @@ -168,6 +171,7 @@ private fun TrackInfoItem( maxLines = 1, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurface, ) } VerticalDivider() @@ -254,6 +258,7 @@ private fun TrackDetailsItem( overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.bodyMedium, textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurface, ) } } @@ -312,3 +317,12 @@ private fun TrackInfoItemMenu( } } } + +@ThemePreviews +@Composable +private fun TrackInfoDialogHomePreviews( + @PreviewParameter(TrackInfoDialogHomePreviewProvider::class) + content: @Composable () -> Unit, +) { + TachiyomiTheme { content() } +} diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt new file mode 100644 index 000000000..00ef15ff1 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt @@ -0,0 +1,81 @@ +package eu.kanade.presentation.track + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import eu.kanade.tachiyomi.dev.preview.DummyTracker +import eu.kanade.tachiyomi.ui.manga.track.TrackItem +import tachiyomi.domain.track.model.Track +import java.text.DateFormat + +internal class TrackInfoDialogHomePreviewProvider : + PreviewParameterProvider<@Composable () -> Unit> { + + private val aTrack = Track( + id = 1L, + mangaId = 2L, + syncId = 3L, + remoteId = 4L, + libraryId = null, + title = "Manage Name On Tracker Site", + lastChapterRead = 2.0, + totalChapters = 12L, + status = 1L, + score = 2.0, + remoteUrl = "https://example.com", + startDate = 0L, + finishDate = 0L, + ) + private val trackItemWithoutTrack = TrackItem( + track = null, + tracker = DummyTracker( + id = 1L, + name = "Example Tracker", + ), + ) + private val trackItemWithTrack = TrackItem( + track = aTrack, + tracker = DummyTracker( + id = 2L, + name = "Example Tracker 2", + ), + ) + + private val trackersWithAndWithoutTrack = @Composable { + TrackInfoDialogHome( + trackItems = listOf( + trackItemWithoutTrack, + trackItemWithTrack, + ), + dateFormat = DateFormat.getDateInstance(), + onStatusClick = {}, + onChapterClick = {}, + onScoreClick = {}, + onStartDateEdit = {}, + onEndDateEdit = {}, + onNewSearch = {}, + onOpenInBrowser = {}, + onRemoved = {}, + ) + } + + private val noTrackers = @Composable { + TrackInfoDialogHome( + trackItems = listOf(), + dateFormat = DateFormat.getDateInstance(), + onStatusClick = {}, + onChapterClick = {}, + onScoreClick = {}, + onStartDateEdit = {}, + onEndDateEdit = {}, + onNewSearch = {}, + onOpenInBrowser = {}, + onRemoved = {}, + ) + } + + override val values: Sequence<@Composable () -> Unit> + get() = sequenceOf( + trackersWithAndWithoutTrack, + noTrackers, + ) +} 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 42ff82007..b3afd2b28 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt @@ -30,12 +30,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import tachiyomi.presentation.core.components.ScrollbarLazyColumn 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 @@ -218,3 +220,25 @@ private fun BaseSelector( }, ) } + +@ThemePreviews +@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 = {}, + ) + } +} 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 8781faaa0..591d371cf 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt @@ -57,8 +57,10 @@ 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.PreviewParameter import androidx.compose.ui.unit.dp import eu.kanade.presentation.manga.components.MangaCover +import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.model.TrackSearch import tachiyomi.presentation.core.components.ScrollbarLazyColumn @@ -66,6 +68,7 @@ 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 @@ -316,3 +319,12 @@ private fun SearchResultItemDetails( ) } } + +@ThemePreviews +@Composable +private fun TrackerSearchPreviews( + @PreviewParameter(TrackerSearchPreviewProvider::class) + content: @Composable () -> Unit, +) { + TachiyomiTheme { content() } +} diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackerSearchPreviewProvider.kt b/app/src/main/java/eu/kanade/presentation/track/TrackerSearchPreviewProvider.kt new file mode 100644 index 000000000..b945e2ad4 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/track/TrackerSearchPreviewProvider.kt @@ -0,0 +1,84 @@ +package eu.kanade.presentation.track + +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.tooling.preview.datasource.LoremIpsum +import eu.kanade.tachiyomi.data.track.model.TrackSearch +import java.time.Instant +import java.time.temporal.ChronoUnit +import kotlin.random.Random + +internal class TrackerSearchPreviewProvider : PreviewParameterProvider<@Composable () -> Unit> { + private val fullPageWithSecondSelected = @Composable { + val items = someTrackSearches().take(30).toList() + TrackerSearch( + query = TextFieldValue(text = "search text"), + onQueryChange = {}, + onDispatchQuery = {}, + queryResult = Result.success(items), + selected = items[1], + onSelectedChange = {}, + onConfirmSelection = {}, + onDismissRequest = {}, + ) + } + private val fullPageWithoutSelected = @Composable { + TrackerSearch( + query = TextFieldValue(text = ""), + onQueryChange = {}, + onDispatchQuery = {}, + queryResult = Result.success(someTrackSearches().take(30).toList()), + selected = null, + onSelectedChange = {}, + onConfirmSelection = {}, + onDismissRequest = {}, + ) + } + private val loading = @Composable { + TrackerSearch( + query = TextFieldValue(), + onQueryChange = {}, + onDispatchQuery = {}, + queryResult = null, + selected = null, + onSelectedChange = {}, + onConfirmSelection = {}, + onDismissRequest = {}, + ) + } + override val values: Sequence<@Composable () -> Unit> = sequenceOf( + fullPageWithSecondSelected, + fullPageWithoutSelected, + loading, + ) + + private fun someTrackSearches(): Sequence = sequence { + while (true) { + yield(randTrackSearch()) + } + } + + private fun randTrackSearch() = TrackSearch().let { + it.id = Random.nextLong() + it.manga_id = Random.nextLong() + it.sync_id = Random.nextInt() + it.media_id = Random.nextLong() + it.library_id = Random.nextLong() + it.title = lorem((1..10).random()).joinToString() + it.last_chapter_read = (0..100).random().toFloat() + it.total_chapters = (100..1000).random() + it.score = (0..10).random().toFloat() + it.status = Random.nextInt() + it.started_reading_date = 0L + it.finished_reading_date = 0L + it.tracking_url = "https://example.com/tracker-example" + it.cover_url = "https://example.com/cover.png" + it.start_date = Instant.now().minus((1L..365).random(), ChronoUnit.DAYS).toString() + it.summary = lorem((0..40).random()).joinToString() + it + } + + private fun lorem(words: Int): Sequence = + LoremIpsum(words).values +} 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 52bf66575..63b7c6d02 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,8 +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.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 @@ -39,3 +42,17 @@ fun TrackLogoIcon( ) } } + +@ThemePreviews +@Composable +private fun TrackLogoIconPreviews( + @PreviewParameter(TrackLogoIconPreviewProvider::class) + tracker: Tracker, +) { + TachiyomiTheme { + TrackLogoIcon( + tracker = tracker, + onClick = null, + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt new file mode 100644 index 000000000..aeaa577a1 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt @@ -0,0 +1,20 @@ +package eu.kanade.presentation.track.components + +import android.graphics.Color +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.track.Tracker +import eu.kanade.tachiyomi.dev.preview.DummyTracker + +internal class TrackLogoIconPreviewProvider : PreviewParameterProvider { + + override val values: Sequence + get() = sequenceOf( + DummyTracker( + id = 1L, + name = "Dummy Tracker", + valLogoColor = Color.rgb(18, 25, 35), + valLogo = R.drawable.ic_tracker_anilist, + ), + ) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt b/app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt new file mode 100644 index 000000000..2315912ba --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt @@ -0,0 +1,115 @@ +package eu.kanade.tachiyomi.dev.preview + +import android.graphics.Color +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.track.Tracker +import eu.kanade.tachiyomi.data.track.model.TrackSearch +import okhttp3.OkHttpClient +import tachiyomi.domain.track.model.Track + +data class DummyTracker( + override val id: Long, + override val name: String, + override val supportsReadingDates: Boolean = false, + override val isLoggedIn: Boolean = false, + val valLogoColor: Int = Color.rgb(18, 25, 35), + val valLogo: Int = R.drawable.ic_tracker_anilist, + val valStatuses: List = (1..6).toList(), + val valReadingStatus: Int = 1, + val valRereadingStatus: Int = 1, + val valCompletionStatus: Int = 2, + val valScoreList: List = (0..10).map(Int::toString), + val val10PointScore: Double = 5.4, + val valSearchResults: List = listOf(), +) : Tracker { + + override val client: OkHttpClient + get() = TODO("Not yet implemented") + + override fun getLogoColor(): Int = valLogoColor + + override fun getLogo(): Int = valLogo + + override fun getStatusList(): List = valStatuses + + override fun getStatus(status: Int): Int? = when (status) { + 1 -> R.string.reading + 2 -> R.string.plan_to_read + 3 -> R.string.completed + 4 -> R.string.on_hold + 5 -> R.string.dropped + 6 -> R.string.repeating + else -> null + } + + override fun getReadingStatus(): Int = valReadingStatus + + override fun getRereadingStatus(): Int = valRereadingStatus + + override fun getCompletionStatus(): Int = valCompletionStatus + + override fun getScoreList(): List = valScoreList + + override fun get10PointScore(track: Track): Double = val10PointScore + + override fun indexToScore(index: Int): Float = getScoreList()[index].toFloat() + + override fun displayScore(track: eu.kanade.tachiyomi.data.database.models.Track): String = + track.score.toString() + + override suspend fun update( + track: eu.kanade.tachiyomi.data.database.models.Track, + didReadChapter: Boolean, + ): eu.kanade.tachiyomi.data.database.models.Track = track + + override suspend fun bind( + track: eu.kanade.tachiyomi.data.database.models.Track, + hasReadChapters: Boolean, + ): eu.kanade.tachiyomi.data.database.models.Track = track + + override suspend fun search(query: String): List = valSearchResults + + override suspend fun refresh( + track: eu.kanade.tachiyomi.data.database.models.Track, + ): eu.kanade.tachiyomi.data.database.models.Track = track + + override suspend fun login(username: String, password: String) = Unit + + override fun logout() = Unit + + override fun getUsername(): String = "username" + + override fun getPassword(): String = "passw0rd" + + override fun saveCredentials(username: String, password: String) = Unit + + override suspend fun register( + item: eu.kanade.tachiyomi.data.database.models.Track, + mangaId: Long, + ) = Unit + + override suspend fun setRemoteStatus( + track: eu.kanade.tachiyomi.data.database.models.Track, + status: Int, + ) = Unit + + override suspend fun setRemoteLastChapterRead( + track: eu.kanade.tachiyomi.data.database.models.Track, + chapterNumber: Int, + ) = Unit + + override suspend fun setRemoteScore( + track: eu.kanade.tachiyomi.data.database.models.Track, + scoreString: String, + ) = Unit + + override suspend fun setRemoteStartDate( + track: eu.kanade.tachiyomi.data.database.models.Track, + epochMillis: Long, + ) = Unit + + override suspend fun setRemoteFinishDate( + track: eu.kanade.tachiyomi.data.database.models.Track, + epochMillis: Long, + ) = Unit +} From 012854dd1e13eedecd92419fd6a4d1d5cc900462 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 22 Oct 2023 15:54:31 -0400 Subject: [PATCH 36/37] Update Voyager --- .../presentation/browse/BrowseSourceScreen.kt | 3 +- .../screen/advanced/ClearDatabaseScreen.kt | 4 +- .../extension/ExtensionFilterScreenModel.kt | 4 +- .../browse/extension/ExtensionsScreenModel.kt | 16 ++--- .../details/ExtensionDetailsScreenModel.kt | 4 +- .../manga/MigrateMangaScreenModel.kt | 4 +- .../MigrateSearchScreenDialogScreenModel.kt | 4 +- .../search/MigrateSearchScreenModel.kt | 4 +- .../sources/MigrateSourceScreenModel.kt | 8 +-- .../browse/source/SourcesFilterScreenModel.kt | 4 +- .../ui/browse/source/SourcesScreenModel.kt | 4 +- .../source/browse/BrowseSourceScreenModel.kt | 10 ++-- .../ui/category/CategoryScreenModel.kt | 16 ++--- .../ui/deeplink/DeepLinkScreenModel.kt | 4 +- .../ui/download/DownloadQueueScreenModel.kt | 6 +- .../ui/history/HistoryScreenModel.kt | 12 ++-- .../ui/library/LibraryScreenModel.kt | 24 ++++---- .../ui/library/LibrarySettingsScreenModel.kt | 4 +- .../ui/manga/MangaCoverScreenModel.kt | 16 ++--- .../tachiyomi/ui/manga/MangaScreenModel.kt | 60 +++++++++---------- .../ui/manga/track/TrackInfoDialog.kt | 26 ++++---- .../eu/kanade/tachiyomi/ui/more/MoreTab.kt | 8 +-- .../tachiyomi/ui/stats/StatsScreenModel.kt | 4 +- .../ui/updates/UpdatesScreenModel.kt | 22 +++---- gradle/libs.versions.toml | 2 +- 25 files changed, 136 insertions(+), 137 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 17943f8b2..f399bb5b8 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt @@ -5,7 +5,6 @@ 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 @@ -98,7 +97,7 @@ fun BrowseSourceContent( ), EmptyScreenAction( stringResId = R.string.label_help, - icon = Icons.Outlined.HelpOutline, + icon = Icons.AutoMirrored.Outlined.HelpOutline, onClick = onHelpClick, ), ) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearDatabaseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearDatabaseScreen.kt index f05b4bcf9..2c3d3337f 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearDatabaseScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearDatabaseScreen.kt @@ -31,8 +31,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastMap import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope import cafe.adriel.voyager.core.model.rememberScreenModel +import cafe.adriel.voyager.core.model.screenModelScope import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.browse.components.SourceIcon @@ -210,7 +210,7 @@ private class ClearDatabaseScreenModel : StateScreenModel mutableState.update { old -> diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterScreenModel.kt index bb8116428..c50a3d9e9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterScreenModel.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.extension import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.extension.interactor.GetExtensionLanguages import eu.kanade.domain.source.interactor.ToggleLanguage import eu.kanade.domain.source.service.SourcePreferences @@ -29,7 +29,7 @@ class ExtensionFilterScreenModel( val events: Flow = _events.receiveAsFlow() init { - coroutineScope.launch { + screenModelScope.launch { combine( getExtensionLanguages.subscribe(), preferences.enabledLanguages().changes(), 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 a1a92f142..7bef3a4c1 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 @@ -4,7 +4,7 @@ import android.app.Application import androidx.annotation.StringRes import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.extension.interactor.GetExtensionsByType import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.presentation.components.SEARCH_DEBOUNCE_MILLIS @@ -74,7 +74,7 @@ class ExtensionsScreenModel( } } - coroutineScope.launchIO { + screenModelScope.launchIO { combine( state.map { it.searchQuery }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS), _currentDownloads, @@ -118,11 +118,11 @@ class ExtensionsScreenModel( } } - coroutineScope.launchIO { findAvailableExtensions() } + screenModelScope.launchIO { findAvailableExtensions() } preferences.extensionUpdatesCount().changes() .onEach { mutableState.update { state -> state.copy(updates = it) } } - .launchIn(coroutineScope) + .launchIn(screenModelScope) } fun search(query: String?) { @@ -132,7 +132,7 @@ class ExtensionsScreenModel( } fun updateAllExtensions() { - coroutineScope.launchIO { + screenModelScope.launchIO { state.value.items.values.flatten() .map { it.extension } .filterIsInstance() @@ -142,13 +142,13 @@ class ExtensionsScreenModel( } fun installExtension(extension: Extension.Available) { - coroutineScope.launchIO { + screenModelScope.launchIO { extensionManager.installExtension(extension).collectToInstallUpdate(extension) } } fun updateExtension(extension: Extension.Installed) { - coroutineScope.launchIO { + screenModelScope.launchIO { extensionManager.updateExtension(extension).collectToInstallUpdate(extension) } } @@ -176,7 +176,7 @@ class ExtensionsScreenModel( } fun findAvailableExtensions() { - coroutineScope.launchIO { + screenModelScope.launchIO { mutableState.update { it.copy(isRefreshing = true) } extensionManager.findAvailableExtensions() 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 c88ea5b42..a3d9b2432 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 @@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.ui.browse.extension.details import android.content.Context import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.extension.interactor.ExtensionSourceItem import eu.kanade.domain.extension.interactor.GetExtensionSources import eu.kanade.domain.source.interactor.ToggleSource @@ -44,7 +44,7 @@ class ExtensionDetailsScreenModel( val events: Flow = _events.receiveAsFlow() init { - coroutineScope.launch { + screenModelScope.launch { launch { extensionManager.installedExtensionsFlow .map { it.firstOrNull { extension -> extension.pkgName == pkgName } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrateMangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrateMangaScreenModel.kt index 7485a22df..2eb4085d6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrateMangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrateMangaScreenModel.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.migration.manga import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.tachiyomi.source.Source import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow @@ -30,7 +30,7 @@ class MigrateMangaScreenModel( val events: Flow = _events.receiveAsFlow() init { - coroutineScope.launch { + screenModelScope.launch { mutableState.update { state -> state.copy(source = sourceManager.getOrStub(sourceId)) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenDialogScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenDialogScreenModel.kt index 887d35feb..a053d45ba 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenDialogScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenDialogScreenModel.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.migration.search import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import tachiyomi.domain.manga.interactor.GetManga @@ -16,7 +16,7 @@ class MigrateSearchScreenDialogScreenModel( ) : StateScreenModel(State()) { init { - coroutineScope.launch { + screenModelScope.launch { val manga = getManga.await(mangaId)!! mutableState.update { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt index 73bba479a..d22756c78 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt @@ -1,6 +1,6 @@ package eu.kanade.tachiyomi.ui.browse.migration.search -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchScreenModel import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter @@ -16,7 +16,7 @@ class MigrateSearchScreenModel( ) : SearchScreenModel() { init { - coroutineScope.launch { + screenModelScope.launch { val manga = getManga.await(mangaId)!! mutableState.update { it.copy( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceScreenModel.kt index f6b4b0441..2fd7e1c27 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceScreenModel.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.migration.sources import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount import eu.kanade.domain.source.interactor.SetMigrateSorting import eu.kanade.domain.source.service.SourcePreferences @@ -30,7 +30,7 @@ class MigrateSourceScreenModel( val channel = _channel.receiveAsFlow() init { - coroutineScope.launchIO { + screenModelScope.launchIO { getSourcesWithFavoriteCount.subscribe() .catch { logcat(LogPriority.ERROR, it) @@ -48,11 +48,11 @@ class MigrateSourceScreenModel( preferences.migrationSortingDirection().changes() .onEach { mutableState.update { state -> state.copy(sortingDirection = it) } } - .launchIn(coroutineScope) + .launchIn(screenModelScope) preferences.migrationSortingMode().changes() .onEach { mutableState.update { state -> state.copy(sortingMode = it) } } - .launchIn(coroutineScope) + .launchIn(screenModelScope) } fun toggleSortingMode() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesFilterScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesFilterScreenModel.kt index 618bf8bd5..4f4ff301c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesFilterScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesFilterScreenModel.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.source import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.source.interactor.GetLanguagesWithSources import eu.kanade.domain.source.interactor.ToggleLanguage import eu.kanade.domain.source.interactor.ToggleSource @@ -25,7 +25,7 @@ class SourcesFilterScreenModel( ) : StateScreenModel(State.Loading) { init { - coroutineScope.launch { + screenModelScope.launch { combine( getLanguagesWithSources.subscribe(), preferences.enabledLanguages().changes(), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesScreenModel.kt index d191fdf15..1435eea3c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesScreenModel.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.source import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.source.interactor.GetEnabledSources import eu.kanade.domain.source.interactor.ToggleSource import eu.kanade.domain.source.interactor.ToggleSourcePin @@ -31,7 +31,7 @@ class SourcesScreenModel( val events = _events.receiveAsFlow() init { - coroutineScope.launchIO { + screenModelScope.launchIO { getEnabledSources.subscribe() .catch { logcat(LogPriority.ERROR, it) 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 b99a67608..2abd5e0ac 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 @@ -12,7 +12,7 @@ import androidx.paging.cachedIn import androidx.paging.filter import androidx.paging.map import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.core.preference.asState import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.manga.interactor.UpdateManga @@ -72,7 +72,7 @@ class BrowseSourceScreenModel( private val addTracks: AddTracks = Injekt.get(), ) : StateScreenModel(State(Listing.valueOf(listingQuery))) { - var displayMode by sourcePreferences.sourceDisplayMode().asState(coroutineScope) + var displayMode by sourcePreferences.sourceDisplayMode().asState(screenModelScope) val source = sourceManager.getOrStub(sourceId) @@ -220,7 +220,7 @@ class BrowseSourceScreenModel( * @param manga the manga to update. */ fun changeMangaFavorite(manga: Manga) { - coroutineScope.launch { + screenModelScope.launch { var new = manga.copy( favorite = !manga.favorite, dateAdded = when (manga.favorite) { @@ -241,7 +241,7 @@ class BrowseSourceScreenModel( } fun addFavorite(manga: Manga) { - coroutineScope.launch { + screenModelScope.launch { val categories = getCategories() val defaultCategoryId = libraryPreferences.defaultCategory().get() val defaultCategory = categories.find { it.id == defaultCategoryId.toLong() } @@ -291,7 +291,7 @@ class BrowseSourceScreenModel( } fun moveMangaToCategories(manga: Manga, categoryIds: List) { - coroutineScope.launchIO { + screenModelScope.launchIO { setMangaCategories.await( mangaId = manga.id, categoryIds = categoryIds.toList(), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt index 3a04a3475..a4a4fe309 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt @@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.ui.category import androidx.annotation.StringRes import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.tachiyomi.R import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.collectLatest @@ -31,7 +31,7 @@ class CategoryScreenModel( val events = _events.receiveAsFlow() init { - coroutineScope.launch { + screenModelScope.launch { getCategories.subscribe() .collectLatest { categories -> mutableState.update { @@ -44,7 +44,7 @@ class CategoryScreenModel( } fun createCategory(name: String) { - coroutineScope.launch { + screenModelScope.launch { when (createCategoryWithName.await(name)) { is CreateCategoryWithName.Result.InternalError -> _events.send(CategoryEvent.InternalError) else -> {} @@ -53,7 +53,7 @@ class CategoryScreenModel( } fun deleteCategory(categoryId: Long) { - coroutineScope.launch { + screenModelScope.launch { when (deleteCategory.await(categoryId = categoryId)) { is DeleteCategory.Result.InternalError -> _events.send(CategoryEvent.InternalError) else -> {} @@ -62,7 +62,7 @@ class CategoryScreenModel( } fun sortAlphabetically() { - coroutineScope.launch { + screenModelScope.launch { when (reorderCategory.sortAlphabetically()) { is ReorderCategory.Result.InternalError -> _events.send(CategoryEvent.InternalError) else -> {} @@ -71,7 +71,7 @@ class CategoryScreenModel( } fun moveUp(category: Category) { - coroutineScope.launch { + screenModelScope.launch { when (reorderCategory.moveUp(category)) { is ReorderCategory.Result.InternalError -> _events.send(CategoryEvent.InternalError) else -> {} @@ -80,7 +80,7 @@ class CategoryScreenModel( } fun moveDown(category: Category) { - coroutineScope.launch { + screenModelScope.launch { when (reorderCategory.moveDown(category)) { is ReorderCategory.Result.InternalError -> _events.send(CategoryEvent.InternalError) else -> {} @@ -89,7 +89,7 @@ class CategoryScreenModel( } fun renameCategory(category: Category, name: String) { - coroutineScope.launch { + screenModelScope.launch { when (renameCategory.await(category, name)) { is RenameCategory.Result.InternalError -> _events.send(CategoryEvent.InternalError) else -> {} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt index bd10f8a6c..51a39ea0a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.deeplink import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.manga.model.toSManga @@ -32,7 +32,7 @@ class DeepLinkScreenModel( ) : StateScreenModel(State.Loading) { init { - coroutineScope.launchIO { + screenModelScope.launchIO { val source = sourceManager.getCatalogueSources() .filterIsInstance() .firstOrNull { it.getUriType(query) != UriType.Unknown } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt index 18ab4c36b..3cfb3ff1a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.download import android.view.MenuItem import cafe.adriel.voyager.core.model.ScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.model.Download @@ -114,7 +114,7 @@ class DownloadQueueScreenModel( } init { - coroutineScope.launch { + screenModelScope.launch { downloadManager.queueState .map { downloads -> downloads @@ -208,7 +208,7 @@ class DownloadQueueScreenModel( * @param download the download to observe its progress. */ private fun launchProgressJob(download: Download) { - val job = coroutineScope.launch { + val job = screenModelScope.launch { while (download.pages == null) { delay(50) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryScreenModel.kt index 582f6a36c..960b66c3a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryScreenModel.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.history import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.core.util.insertSeparators import eu.kanade.presentation.history.HistoryUiModel import eu.kanade.tachiyomi.util.lang.toDateKey @@ -40,7 +40,7 @@ class HistoryScreenModel( val events: Flow = _events.receiveAsFlow() init { - coroutineScope.launch { + screenModelScope.launch { state.map { it.searchQuery } .distinctUntilChanged() .flatMapLatest { query -> @@ -75,7 +75,7 @@ class HistoryScreenModel( } fun getNextChapterForManga(mangaId: Long, chapterId: Long) { - coroutineScope.launchIO { + screenModelScope.launchIO { sendNextChapterEvent(getNextChapters.await(mangaId, chapterId, onlyUnread = false)) } } @@ -86,19 +86,19 @@ class HistoryScreenModel( } fun removeFromHistory(history: HistoryWithRelations) { - coroutineScope.launchIO { + screenModelScope.launchIO { removeHistory.await(history) } } fun removeAllFromHistory(mangaId: Long) { - coroutineScope.launchIO { + screenModelScope.launchIO { removeHistory.await(mangaId) } } fun removeAllHistory() { - coroutineScope.launchIO { + screenModelScope.launchIO { val result = removeHistory.awaitAll() if (!result) return@launchIO _events.send(Event.HistoryCleared) 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 3f0408094..6d16364c3 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 @@ -6,7 +6,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.util.fastAny import androidx.compose.ui.util.fastMap import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.core.preference.PreferenceMutableState import eu.kanade.core.preference.asState import eu.kanade.core.util.fastDistinctBy @@ -91,10 +91,10 @@ class LibraryScreenModel( private val trackerManager: TrackerManager = Injekt.get(), ) : StateScreenModel(State()) { - var activeCategoryIndex: Int by libraryPreferences.lastUsedCategory().asState(coroutineScope) + var activeCategoryIndex: Int by libraryPreferences.lastUsedCategory().asState(screenModelScope) init { - coroutineScope.launchIO { + screenModelScope.launchIO { combine( state.map { it.searchQuery }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS), getLibraryFlow(), @@ -139,7 +139,7 @@ class LibraryScreenModel( ) } } - .launchIn(coroutineScope) + .launchIn(screenModelScope) combine( getLibraryItemPreferencesFlow(), @@ -161,7 +161,7 @@ class LibraryScreenModel( state.copy(hasActiveFilters = it) } } - .launchIn(coroutineScope) + .launchIn(screenModelScope) } /** @@ -429,7 +429,7 @@ class LibraryScreenModel( * @param amount the amount to queue or null to queue all */ private fun downloadUnreadChapters(mangas: List, amount: Int?) { - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { mangas.forEach { manga -> val chapters = getNextChapters.await(manga.id) .fastFilterNot { chapter -> @@ -453,7 +453,7 @@ class LibraryScreenModel( */ fun markReadSelection(read: Boolean) { val mangas = state.value.selection.toList() - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { mangas.forEach { manga -> setReadStatus.await( manga = manga.manga, @@ -472,7 +472,7 @@ class LibraryScreenModel( * @param deleteChapters whether to delete downloaded chapters. */ fun removeMangas(mangaList: List, deleteFromLibrary: Boolean, deleteChapters: Boolean) { - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { val mangaToDelete = mangaList.distinctBy { it.id } if (deleteFromLibrary) { @@ -505,7 +505,7 @@ class LibraryScreenModel( * @param removeCategories the categories to remove in all mangas. */ fun setMangaCategories(mangaList: List, addCategories: List, removeCategories: List) { - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { mangaList.forEach { manga -> val categoryIds = getCategories.await(manga.id) .map { it.id } @@ -519,11 +519,11 @@ class LibraryScreenModel( } fun getDisplayMode(): PreferenceMutableState { - return libraryPreferences.displayMode().asState(coroutineScope) + return libraryPreferences.displayMode().asState(screenModelScope) } fun getColumnsPreferenceForCurrentOrientation(isLandscape: Boolean): PreferenceMutableState { - return (if (isLandscape) libraryPreferences.landscapeColumns() else libraryPreferences.portraitColumns()).asState(coroutineScope) + return (if (isLandscape) libraryPreferences.landscapeColumns() else libraryPreferences.portraitColumns()).asState(screenModelScope) } suspend fun getRandomLibraryItemForCurrentCategory(): LibraryItem? { @@ -626,7 +626,7 @@ class LibraryScreenModel( } fun openChangeCategoryDialog() { - coroutineScope.launchIO { + screenModelScope.launchIO { // Create a copy of selected manga val mangaList = state.value.selection.map { it.manga } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt index 2a59af85c..ce573de3f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt @@ -1,7 +1,7 @@ package eu.kanade.tachiyomi.ui.library import cafe.adriel.voyager.core.model.ScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.base.BasePreferences import eu.kanade.tachiyomi.data.track.TrackerManager import tachiyomi.core.preference.Preference @@ -43,7 +43,7 @@ class LibrarySettingsScreenModel( } fun setSort(category: Category?, mode: LibrarySort.Type, direction: LibrarySort.Direction) { - coroutineScope.launchIO { + screenModelScope.launchIO { setSortModeForCategory.await(category, mode, direction) } } 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 784a99aa2..f1a7377e1 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 @@ -4,7 +4,7 @@ import android.content.Context import android.net.Uri import androidx.compose.material3.SnackbarHostState import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import coil.imageLoader import coil.request.ImageRequest import coil.size.Size @@ -40,14 +40,14 @@ class MangaCoverScreenModel( ) : StateScreenModel(null) { init { - coroutineScope.launchIO { + screenModelScope.launchIO { getManga.subscribe(mangaId) .collect { newManga -> mutableState.update { newManga } } } } fun saveCover(context: Context) { - coroutineScope.launch { + screenModelScope.launch { try { saveCoverInternal(context, temp = false) snackbarHostState.showSnackbar( @@ -65,7 +65,7 @@ class MangaCoverScreenModel( } fun shareCover(context: Context) { - coroutineScope.launch { + screenModelScope.launch { try { val uri = saveCoverInternal(context, temp = true) ?: return@launch withUIContext { @@ -117,7 +117,7 @@ class MangaCoverScreenModel( */ fun editCover(context: Context, data: Uri) { val manga = state.value ?: return - coroutineScope.launchIO { + screenModelScope.launchIO { context.contentResolver.openInputStream(data)?.use { try { manga.editCover(Injekt.get(), it, updateManga, coverCache) @@ -131,7 +131,7 @@ class MangaCoverScreenModel( fun deleteCustomCover(context: Context) { val mangaId = state.value?.id ?: return - coroutineScope.launchIO { + screenModelScope.launchIO { try { coverCache.deleteCustomCover(mangaId) updateManga.awaitUpdateCoverLastModified(mangaId) @@ -143,7 +143,7 @@ class MangaCoverScreenModel( } private fun notifyCoverUpdated(context: Context) { - coroutineScope.launch { + screenModelScope.launch { snackbarHostState.showSnackbar( context.getString(R.string.cover_updated), withDismissAction = true, @@ -152,7 +152,7 @@ class MangaCoverScreenModel( } private fun notifyFailedCoverUpdate(context: Context, e: Throwable) { - coroutineScope.launch { + screenModelScope.launch { snackbarHostState.showSnackbar( context.getString(R.string.notification_cover_update_failed), withDismissAction = true, 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 8d1bace7d..95feba487 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 @@ -7,7 +7,7 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.core.preference.asState import eu.kanade.core.util.addOrRemove import eu.kanade.domain.chapter.interactor.SetReadStatus @@ -126,9 +126,9 @@ class MangaScreenModel( val chapterSwipeStartAction = libraryPreferences.swipeToEndAction().get() val chapterSwipeEndAction = libraryPreferences.swipeToStartAction().get() - val relativeTime by uiPreferences.relativeTime().asState(coroutineScope) + val relativeTime by uiPreferences.relativeTime().asState(screenModelScope) val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get())) - private val skipFiltered by readerPreferences.skipFiltered().asState(coroutineScope) + private val skipFiltered by readerPreferences.skipFiltered().asState(screenModelScope) val isUpdateIntervalEnabled = LibraryPreferences.MANGA_OUTSIDE_RELEASE_PERIOD in libraryPreferences.autoUpdateMangaRestrictions().get() @@ -148,7 +148,7 @@ class MangaScreenModel( } init { - coroutineScope.launchIO { + screenModelScope.launchIO { combine( getMangaAndChapters.subscribe(mangaId).distinctUntilChanged(), downloadCache.changes, @@ -166,7 +166,7 @@ class MangaScreenModel( observeDownloads() - coroutineScope.launchIO { + screenModelScope.launchIO { val manga = getMangaAndChapters.awaitManga(mangaId) val chapters = getMangaAndChapters.awaitChapters(mangaId) .toChapterItems(manga) @@ -194,7 +194,7 @@ class MangaScreenModel( observeTrackers() // Fetch info-chapters when needed - if (coroutineScope.isActive) { + if (screenModelScope.isActive) { val fetchFromSourceTasks = listOf( async { if (needRefreshInfo) fetchMangaFromSource() }, async { if (needRefreshChapter) fetchChaptersFromSource() }, @@ -208,7 +208,7 @@ class MangaScreenModel( } fun fetchAllFromSource(manualFetch: Boolean = true) { - coroutineScope.launch { + screenModelScope.launch { updateSuccessState { it.copy(isRefreshingData = true) } val fetchFromSourceTasks = listOf( async { fetchMangaFromSource(manualFetch) }, @@ -236,7 +236,7 @@ class MangaScreenModel( if (e is HttpException && e.code == 103) return logcat(LogPriority.ERROR, e) - coroutineScope.launch { + screenModelScope.launch { snackbarHostState.showSnackbar(message = with(context) { e.formattedMessage }) } } @@ -245,7 +245,7 @@ class MangaScreenModel( fun toggleFavorite() { toggleFavorite( onRemoved = { - coroutineScope.launch { + screenModelScope.launch { if (!hasDownloads()) return@launch val result = snackbarHostState.showSnackbar( message = context.getString(R.string.delete_downloads_for_manga), @@ -268,7 +268,7 @@ class MangaScreenModel( checkDuplicate: Boolean = true, ) { val state = successState ?: return - coroutineScope.launchIO { + screenModelScope.launchIO { val manga = state.manga if (isFavorited) { @@ -323,7 +323,7 @@ class MangaScreenModel( fun showChangeCategoryDialog() { val manga = successState?.manga ?: return - coroutineScope.launch { + screenModelScope.launch { val categories = getCategories() val selection = getMangaCategoryIds(manga) updateSuccessState { successState -> @@ -345,7 +345,7 @@ class MangaScreenModel( } fun setFetchInterval(manga: Manga, interval: Int) { - coroutineScope.launchIO { + screenModelScope.launchIO { updateManga.awaitUpdateFetchInterval( // Custom intervals are negative manga.copy(fetchInterval = -interval), @@ -395,7 +395,7 @@ class MangaScreenModel( moveMangaToCategory(categories) if (manga.favorite) return - coroutineScope.launchIO { + screenModelScope.launchIO { updateManga.awaitUpdateFavorite(manga.id, true) } } @@ -411,7 +411,7 @@ class MangaScreenModel( } private fun moveMangaToCategory(categoryIds: List) { - coroutineScope.launchIO { + screenModelScope.launchIO { setMangaCategories.await(mangaId, categoryIds) } } @@ -430,7 +430,7 @@ class MangaScreenModel( // Chapters list - start private fun observeDownloads() { - coroutineScope.launchIO { + screenModelScope.launchIO { downloadManager.statusFlow() .filter { it.manga.id == successState?.manga?.id } .catch { error -> logcat(LogPriority.ERROR, error) } @@ -441,7 +441,7 @@ class MangaScreenModel( } } - coroutineScope.launchIO { + screenModelScope.launchIO { downloadManager.progressFlow() .filter { it.manga.id == successState?.manga?.id } .catch { error -> logcat(LogPriority.ERROR, error) } @@ -523,7 +523,7 @@ class MangaScreenModel( with(context) { e.formattedMessage } } - coroutineScope.launch { + screenModelScope.launch { snackbarHostState.showSnackbar(message = message) } val newManga = mangaRepository.getMangaById(mangaId) @@ -535,7 +535,7 @@ class MangaScreenModel( * @throws IllegalStateException if the swipe action is [LibraryPreferences.ChapterSwipeAction.Disabled] */ fun chapterSwipe(chapterItem: ChapterItem, swipeAction: LibraryPreferences.ChapterSwipeAction) { - coroutineScope.launch { + screenModelScope.launch { executeChapterSwipeAction(chapterItem, swipeAction) } } @@ -612,7 +612,7 @@ class MangaScreenModel( updateSuccessState { state -> state.copy(hasPromptedToAddBefore = true) } - coroutineScope.launch { + screenModelScope.launch { val result = snackbarHostState.showSnackbar( message = context.getString(R.string.snack_add_to_library), actionLabel = context.getString(R.string.action_add), @@ -683,7 +683,7 @@ class MangaScreenModel( * @param read whether to mark chapters as read or unread. */ fun markChaptersRead(chapters: List, read: Boolean) { - coroutineScope.launchIO { + screenModelScope.launchIO { setReadStatus.await( read = read, chapters = chapters.toTypedArray(), @@ -707,7 +707,7 @@ class MangaScreenModel( * @param chapters the list of chapters to bookmark. */ fun bookmarkChapters(chapters: List, bookmarked: Boolean) { - coroutineScope.launchIO { + screenModelScope.launchIO { chapters .filterNot { it.bookmark == bookmarked } .map { ChapterUpdate(id = it.id, bookmark = bookmarked) } @@ -722,7 +722,7 @@ class MangaScreenModel( * @param chapters the list of chapters to delete. */ fun deleteChapters(chapters: List) { - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { try { successState?.let { state -> downloadManager.deleteChapters( @@ -738,7 +738,7 @@ class MangaScreenModel( } private fun downloadNewChapters(chapters: List) { - coroutineScope.launchNonCancellable { + 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 @@ -758,7 +758,7 @@ class MangaScreenModel( TriState.ENABLED_IS -> Manga.CHAPTER_SHOW_UNREAD TriState.ENABLED_NOT -> Manga.CHAPTER_SHOW_READ } - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { setMangaChapterFlags.awaitSetUnreadFilter(manga, flag) } } @@ -776,7 +776,7 @@ class MangaScreenModel( TriState.ENABLED_NOT -> Manga.CHAPTER_SHOW_NOT_DOWNLOADED } - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { setMangaChapterFlags.awaitSetDownloadedFilter(manga, flag) } } @@ -794,7 +794,7 @@ class MangaScreenModel( TriState.ENABLED_NOT -> Manga.CHAPTER_SHOW_NOT_BOOKMARKED } - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { setMangaChapterFlags.awaitSetBookmarkFilter(manga, flag) } } @@ -806,7 +806,7 @@ class MangaScreenModel( fun setDisplayMode(mode: Long) { val manga = successState?.manga ?: return - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { setMangaChapterFlags.awaitSetDisplayMode(manga, mode) } } @@ -818,14 +818,14 @@ class MangaScreenModel( fun setSorting(sort: Long) { val manga = successState?.manga ?: return - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { setMangaChapterFlags.awaitSetSortingModeOrFlipOrder(manga, sort) } } fun setCurrentSettingsAsDefault(applyToExisting: Boolean) { val manga = successState?.manga ?: return - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { libraryPreferences.setChapterSettingsDefault(manga) if (applyToExisting) { setMangaDefaultChapterFlags.awaitAll() @@ -929,7 +929,7 @@ class MangaScreenModel( private fun observeTrackers() { val manga = successState?.manga ?: return - coroutineScope.launchIO { + screenModelScope.launchIO { getTracks.subscribe(manga.id) .catch { logcat(LogPriority.ERROR, it) } .map { tracks -> diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index 94e6bbe84..6eb8a0d74 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -34,8 +34,8 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope import cafe.adriel.voyager.core.model.rememberScreenModel +import cafe.adriel.voyager.core.model.screenModelScope import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.currentOrThrow @@ -188,11 +188,11 @@ data class TrackInfoDialogHomeScreen( ) : StateScreenModel(State()) { init { - coroutineScope.launch { + screenModelScope.launch { refreshTrackers() } - coroutineScope.launch { + screenModelScope.launch { getTracks.subscribe(mangaId) .catch { logcat(LogPriority.ERROR, it) } .distinctUntilChanged() @@ -203,7 +203,7 @@ data class TrackInfoDialogHomeScreen( fun registerEnhancedTracking(item: TrackItem) { item.tracker as EnhancedTracker - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { val manga = Injekt.get().await(mangaId) ?: return@launchNonCancellable try { val matchResult = item.tracker.match(manga) ?: throw Exception() @@ -294,7 +294,7 @@ private data class TrackStatusSelectorScreen( } fun setStatus() { - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { tracker.setRemoteStatus(track.toDbTrack(), state.value.selection) } } @@ -353,7 +353,7 @@ private data class TrackChapterSelectorScreen( } fun setChapter() { - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { tracker.setRemoteLastChapterRead(track.toDbTrack(), state.value.selection) } } @@ -407,7 +407,7 @@ private data class TrackScoreSelectorScreen( } fun setScore() { - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { tracker.setRemoteScore(track.toDbTrack(), state.value.selection) } } @@ -533,7 +533,7 @@ private data class TrackDateSelectorScreen( fun setDate(millis: Long) { // Convert to local time val localMillis = millis.convertEpochMillisZone(ZoneOffset.UTC, ZoneOffset.systemDefault()) - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { if (start) { tracker.setRemoteStartDate(track.toDbTrack(), localMillis) } else { @@ -622,7 +622,7 @@ private data class TrackDateRemoverScreen( fun getServiceName() = tracker.name fun removeDate() { - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { if (start) { tracker.setRemoteStartDate(track.toDbTrack(), 0) } else { @@ -685,7 +685,7 @@ data class TrackerSearchScreen( } fun trackingSearch(query: String) { - coroutineScope.launch { + screenModelScope.launch { // To show loading state mutableState.update { it.copy(queryResult = null, selected = null) } @@ -707,7 +707,7 @@ data class TrackerSearchScreen( } fun registerTracking(item: TrackSearch) { - coroutineScope.launchNonCancellable { tracker.register(item, mangaId) } + screenModelScope.launchNonCancellable { tracker.register(item, mangaId) } } fun updateSelection(selected: TrackSearch) { @@ -812,13 +812,13 @@ private data class TrackerRemoveScreen( fun isDeletable() = tracker is DeletableTracker fun deleteMangaFromService() { - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { (tracker as DeletableTracker).delete(track.toDbTrack()) } } fun unregisterTracking(serviceId: Long) { - coroutineScope.launchNonCancellable { deleteTrack.await(mangaId, serviceId) } + screenModelScope.launchNonCancellable { deleteTrack.await(mangaId, serviceId) } } } } 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 ed09839b0..2870b8c44 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 @@ -10,8 +10,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import cafe.adriel.voyager.core.model.ScreenModel -import cafe.adriel.voyager.core.model.coroutineScope import cafe.adriel.voyager.core.model.rememberScreenModel +import cafe.adriel.voyager.core.model.screenModelScope import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.currentOrThrow @@ -83,15 +83,15 @@ private class MoreScreenModel( preferences: BasePreferences = Injekt.get(), ) : ScreenModel { - var downloadedOnly by preferences.downloadedOnly().asState(coroutineScope) - var incognitoMode by preferences.incognitoMode().asState(coroutineScope) + var downloadedOnly by preferences.downloadedOnly().asState(screenModelScope) + var incognitoMode by preferences.incognitoMode().asState(screenModelScope) private var _state: MutableStateFlow = MutableStateFlow(DownloadQueueState.Stopped) val downloadQueueState: StateFlow = _state.asStateFlow() init { // Handle running/paused status change and queue progress updating - coroutineScope.launchIO { + screenModelScope.launchIO { combine( downloadManager.isDownloaderRunning, downloadManager.queueState, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt index 6131308d0..e925c7dcb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt @@ -1,7 +1,7 @@ package eu.kanade.tachiyomi.ui.stats import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.core.util.fastCountNot import eu.kanade.core.util.fastDistinctBy import eu.kanade.core.util.fastFilter @@ -39,7 +39,7 @@ class StatsScreenModel( private val loggedInTrackers by lazy { trackerManager.trackers.fastFilter { it.isLoggedIn } } init { - coroutineScope.launchIO { + screenModelScope.launchIO { val libraryManga = getLibraryManga.await() val distinctLibraryManga = libraryManga.fastDistinctBy { it.id } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt index 62ac21cc1..5dcd140b3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt @@ -7,7 +7,7 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import cafe.adriel.voyager.core.model.StateScreenModel -import cafe.adriel.voyager.core.model.coroutineScope +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 @@ -65,15 +65,15 @@ class UpdatesScreenModel( private val _events: Channel = Channel(Int.MAX_VALUE) val events: Flow = _events.receiveAsFlow() - val lastUpdated by libraryPreferences.lastUpdatedTimestamp().asState(coroutineScope) - val relativeTime by uiPreferences.relativeTime().asState(coroutineScope) + val lastUpdated by libraryPreferences.lastUpdatedTimestamp().asState(screenModelScope) + val relativeTime by uiPreferences.relativeTime().asState(screenModelScope) // First and last selected index in list private val selectedPositions: Array = arrayOf(-1, -1) private val selectedChapterIds: HashSet = HashSet() init { - coroutineScope.launchIO { + screenModelScope.launchIO { // Set date limit for recent chapters val calendar = Calendar.getInstance().apply { time = Date() @@ -99,7 +99,7 @@ class UpdatesScreenModel( } } - coroutineScope.launchIO { + screenModelScope.launchIO { merge(downloadManager.statusFlow(), downloadManager.progressFlow()) .catch { logcat(LogPriority.ERROR, it) } .collect(this@UpdatesScreenModel::updateDownloadState) @@ -131,7 +131,7 @@ class UpdatesScreenModel( fun updateLibrary(): Boolean { val started = LibraryUpdateJob.startNow(Injekt.get()) - coroutineScope.launch { + screenModelScope.launch { _events.send(Event.LibraryUpdateTriggered(started)) } return started @@ -163,7 +163,7 @@ class UpdatesScreenModel( fun downloadChapters(items: List, action: ChapterDownloadAction) { if (items.isEmpty()) return - coroutineScope.launch { + screenModelScope.launch { when (action) { ChapterDownloadAction.START -> { downloadChapters(items) @@ -203,7 +203,7 @@ class UpdatesScreenModel( * @param read whether to mark chapters as read or unread. */ fun markUpdatesRead(updates: List, read: Boolean) { - coroutineScope.launchIO { + screenModelScope.launchIO { setReadStatus.await( read = read, chapters = updates @@ -219,7 +219,7 @@ class UpdatesScreenModel( * @param updates the list of chapters to bookmark. */ fun bookmarkUpdates(updates: List, bookmark: Boolean) { - coroutineScope.launchIO { + screenModelScope.launchIO { updates .filterNot { it.update.bookmark == bookmark } .map { ChapterUpdate(id = it.update.chapterId, bookmark = bookmark) } @@ -233,7 +233,7 @@ class UpdatesScreenModel( * @param updatesItem the list of chapters to download. */ private fun downloadChapters(updatesItem: List) { - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { val groupedUpdates = updatesItem.groupBy { it.update.mangaId }.values for (updates in groupedUpdates) { val mangaId = updates.first().update.mangaId @@ -252,7 +252,7 @@ class UpdatesScreenModel( * @param updatesItem list of chapters */ fun deleteChapters(updatesItem: List) { - coroutineScope.launchNonCancellable { + screenModelScope.launchNonCancellable { updatesItem .groupBy { it.update.mangaId } .entries diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ffd9cabb4..7c629087e 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-rc07" +voyager = "1.0.0-rc08" richtext = "0.17.0" [libraries] From 3b7ed9bc6d99c9822f3051f3696fb8359b4a8f8a Mon Sep 17 00:00:00 2001 From: Caleb Morris Date: Sun, 22 Oct 2023 16:58:16 -0700 Subject: [PATCH 37/37] Detached permission request from DiskUtil (#10051) Being an extension on the DiskUtil couples to a class at a different abstraction layer without really needing to. Created PermissionRequestHelper as a place to put similar requests if needed in the future. --- .../presentation/extensions/DiskUtil.kt | 18 ----------------- .../settings/screen/SettingsBackupScreen.kt | 5 ++--- .../permissions/PermissionRequestHelper.kt | 20 +++++++++++++++++++ .../kanade/tachiyomi/ui/browse/BrowseTab.kt | 5 ++--- 4 files changed, 24 insertions(+), 24 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/presentation/extensions/DiskUtil.kt create mode 100644 app/src/main/java/eu/kanade/presentation/permissions/PermissionRequestHelper.kt diff --git a/app/src/main/java/eu/kanade/presentation/extensions/DiskUtil.kt b/app/src/main/java/eu/kanade/presentation/extensions/DiskUtil.kt deleted file mode 100644 index f0581e099..000000000 --- a/app/src/main/java/eu/kanade/presentation/extensions/DiskUtil.kt +++ /dev/null @@ -1,18 +0,0 @@ -package eu.kanade.presentation.extensions - -import android.Manifest -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import com.google.accompanist.permissions.rememberPermissionState -import eu.kanade.tachiyomi.util.storage.DiskUtil - -/** - * Launches request for [Manifest.permission.WRITE_EXTERNAL_STORAGE] permission - */ -@Composable -fun DiskUtil.RequestStoragePermission() { - val permissionState = rememberPermissionState(permission = Manifest.permission.WRITE_EXTERNAL_STORAGE) - LaunchedEffect(Unit) { - permissionState.launchPermissionRequest() - } -} diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt index e35acffe0..cb9c9907c 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt @@ -33,15 +33,14 @@ 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.extensions.RequestStoragePermission import eu.kanade.presentation.more.settings.Preference +import eu.kanade.presentation.permissions.PermissionRequestHelper 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.util.storage.DiskUtil import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.toast @@ -66,7 +65,7 @@ object SettingsBackupScreen : SearchableSettings { override fun getPreferences(): List { val backupPreferences = Injekt.get() - DiskUtil.RequestStoragePermission() + PermissionRequestHelper.requestStoragePermission() return listOf( getCreateBackupPref(), diff --git a/app/src/main/java/eu/kanade/presentation/permissions/PermissionRequestHelper.kt b/app/src/main/java/eu/kanade/presentation/permissions/PermissionRequestHelper.kt new file mode 100644 index 000000000..7ce28f9da --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/permissions/PermissionRequestHelper.kt @@ -0,0 +1,20 @@ +package eu.kanade.presentation.permissions + +import android.Manifest +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import com.google.accompanist.permissions.rememberPermissionState + +/** + * Launches request for [Manifest.permission.WRITE_EXTERNAL_STORAGE] permission + */ +object PermissionRequestHelper { + + @Composable + fun requestStoragePermission() { + val permissionState = rememberPermissionState(permission = Manifest.permission.WRITE_EXTERNAL_STORAGE) + LaunchedEffect(Unit) { + permissionState.launchPermissionRequest() + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt index d0753ce10..4466cb567 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt @@ -14,7 +14,7 @@ import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.tab.LocalTabNavigator import cafe.adriel.voyager.navigator.tab.TabOptions import eu.kanade.presentation.components.TabbedScreen -import eu.kanade.presentation.extensions.RequestStoragePermission +import eu.kanade.presentation.permissions.PermissionRequestHelper import eu.kanade.presentation.util.Tab import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsScreenModel @@ -23,7 +23,6 @@ import eu.kanade.tachiyomi.ui.browse.migration.sources.migrateSourceTab import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen import eu.kanade.tachiyomi.ui.browse.source.sourcesTab import eu.kanade.tachiyomi.ui.main.MainActivity -import eu.kanade.tachiyomi.util.storage.DiskUtil data class BrowseTab( private val toExtensions: Boolean = false, @@ -66,7 +65,7 @@ data class BrowseTab( ) // For local source - DiskUtil.RequestStoragePermission() + PermissionRequestHelper.requestStoragePermission() LaunchedEffect(Unit) { (context as? MainActivity)?.ready = true