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 fa07b962ff..08f2204ae9 100644 --- a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt @@ -14,8 +14,6 @@ import androidx.compose.material.icons.outlined.Label import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.SettingsBackupRestore import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalUriHandler @@ -31,12 +29,15 @@ import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.more.DownloadQueueState import eu.kanade.tachiyomi.ui.more.MoreController -import eu.kanade.tachiyomi.ui.more.MorePresenter import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView @Composable fun MoreScreen( - presenter: MorePresenter, + downloadQueueStateProvider: () -> DownloadQueueState, + downloadedOnly: Boolean, + onDownloadedOnlyChange: (Boolean) -> Unit, + incognitoMode: Boolean, + onIncognitoModeChange: (Boolean) -> Unit, isFDroid: Boolean, onClickDownloadQueue: () -> Unit, onClickCategories: () -> Unit, @@ -45,7 +46,6 @@ fun MoreScreen( onClickAbout: () -> Unit, ) { val uriHandler = LocalUriHandler.current - val downloadQueueState by presenter.downloadQueueState.collectAsState() ScrollbarLazyColumn( modifier = Modifier.statusBarsPadding(), @@ -70,8 +70,8 @@ fun MoreScreen( item { AppStateBanners( - downloadedOnlyMode = presenter.downloadedOnly.value, - incognitoMode = presenter.incognitoMode.value, + downloadedOnlyMode = downloadedOnly, + incognitoMode = incognitoMode, ) } @@ -80,8 +80,8 @@ fun MoreScreen( title = stringResource(R.string.label_downloaded_only), subtitle = stringResource(R.string.downloaded_only_summary), icon = Icons.Outlined.CloudOff, - checked = presenter.downloadedOnly.value, - onCheckedChanged = { presenter.downloadedOnly.value = it }, + checked = downloadedOnly, + onCheckedChanged = onDownloadedOnlyChange, ) } item { @@ -89,20 +89,21 @@ fun MoreScreen( title = stringResource(R.string.pref_incognito_mode), subtitle = stringResource(R.string.pref_incognito_mode_summary), icon = ImageVector.vectorResource(R.drawable.ic_glasses_24dp), - checked = presenter.incognitoMode.value, - onCheckedChanged = { presenter.incognitoMode.value = it }, + checked = incognitoMode, + onCheckedChanged = onIncognitoModeChange, ) } item { Divider() } item { + val downloadQueueState = downloadQueueStateProvider() TextPreferenceWidget( title = stringResource(R.string.label_download_queue), subtitle = when (downloadQueueState) { DownloadQueueState.Stopped -> null is DownloadQueueState.Paused -> { - val pending = (downloadQueueState as DownloadQueueState.Paused).pending + val pending = downloadQueueState.pending if (pending == 0) { stringResource(R.string.paused) } else { @@ -116,7 +117,7 @@ fun MoreScreen( } } is DownloadQueueState.Downloading -> { - val pending = (downloadQueueState as DownloadQueueState.Downloading).pending + val pending = downloadQueueState.pending pluralStringResource(id = R.plurals.download_queue_summary, count = pending, pending) } }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreController.kt index a0ae9b93d5..f3c4d5bed5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreController.kt @@ -1,32 +1,15 @@ package eu.kanade.tachiyomi.ui.more import androidx.compose.runtime.Composable -import eu.kanade.presentation.more.MoreScreen -import eu.kanade.tachiyomi.ui.base.controller.FullComposeController +import cafe.adriel.voyager.navigator.Navigator +import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController import eu.kanade.tachiyomi.ui.base.controller.RootController -import eu.kanade.tachiyomi.ui.base.controller.pushController -import eu.kanade.tachiyomi.ui.category.CategoryController -import eu.kanade.tachiyomi.ui.download.DownloadController -import eu.kanade.tachiyomi.ui.setting.SettingsMainController -import eu.kanade.tachiyomi.util.system.isInstalledFromFDroid -class MoreController : - FullComposeController(), - RootController { - - override fun createPresenter() = MorePresenter() +class MoreController : BasicFullComposeController(), RootController { @Composable override fun ComposeContent() { - MoreScreen( - presenter = presenter, - isFDroid = activity?.isInstalledFromFDroid() ?: false, - onClickDownloadQueue = { router.pushController(DownloadController()) }, - onClickCategories = { router.pushController(CategoryController()) }, - onClickBackupAndRestore = { router.pushController(SettingsMainController.toBackupScreen()) }, - onClickSettings = { router.pushController(SettingsMainController()) }, - onClickAbout = { router.pushController(SettingsMainController.toAboutScreen()) }, - ) + Navigator(screen = MoreScreen) } companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/MorePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/MorePresenter.kt deleted file mode 100644 index 01291be914..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/MorePresenter.kt +++ /dev/null @@ -1,54 +0,0 @@ -package eu.kanade.tachiyomi.ui.more - -import android.os.Bundle -import eu.kanade.domain.base.BasePreferences -import eu.kanade.tachiyomi.data.download.DownloadManager -import eu.kanade.tachiyomi.data.download.DownloadService -import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import eu.kanade.tachiyomi.util.lang.launchIO -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.combine -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get - -class MorePresenter( - private val downloadManager: DownloadManager = Injekt.get(), - preferences: BasePreferences = Injekt.get(), -) : BasePresenter() { - - val downloadedOnly = preferences.downloadedOnly().asState() - val incognitoMode = preferences.incognitoMode().asState() - - private var _state: MutableStateFlow = MutableStateFlow(DownloadQueueState.Stopped) - val downloadQueueState: StateFlow = _state.asStateFlow() - - override fun onCreate(savedState: Bundle?) { - super.onCreate(savedState) - - // Handle running/paused status change and queue progress updating - presenterScope.launchIO { - combine( - DownloadService.isRunning, - downloadManager.queue.updatedFlow(), - ) { isRunning, downloadQueue -> Pair(isRunning, downloadQueue.size) } - .collectLatest { (isDownloading, downloadQueueSize) -> - val pendingDownloadExists = downloadQueueSize != 0 - _state.value = when { - !pendingDownloadExists -> DownloadQueueState.Stopped - !isDownloading && !pendingDownloadExists -> DownloadQueueState.Paused(0) - !isDownloading && pendingDownloadExists -> DownloadQueueState.Paused(downloadQueueSize) - else -> DownloadQueueState.Downloading(downloadQueueSize) - } - } - } - } -} - -sealed class DownloadQueueState { - object Stopped : DownloadQueueState() - data class Paused(val pending: Int) : DownloadQueueState() - data class Downloading(val pending: Int) : DownloadQueueState() -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreScreen.kt new file mode 100644 index 0000000000..32a32e25e6 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreScreen.kt @@ -0,0 +1,91 @@ +package eu.kanade.tachiyomi.ui.more + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +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.screen.Screen +import cafe.adriel.voyager.navigator.currentOrThrow +import eu.kanade.core.prefs.asState +import eu.kanade.domain.base.BasePreferences +import eu.kanade.presentation.more.MoreScreen +import eu.kanade.presentation.util.LocalRouter +import eu.kanade.tachiyomi.data.download.DownloadManager +import eu.kanade.tachiyomi.data.download.DownloadService +import eu.kanade.tachiyomi.ui.base.controller.pushController +import eu.kanade.tachiyomi.ui.category.CategoryController +import eu.kanade.tachiyomi.ui.download.DownloadController +import eu.kanade.tachiyomi.ui.setting.SettingsMainController +import eu.kanade.tachiyomi.util.lang.launchIO +import eu.kanade.tachiyomi.util.system.isInstalledFromFDroid +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.combine +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +object MoreScreen : Screen { + @Composable + override fun Content() { + val router = LocalRouter.currentOrThrow + val context = LocalContext.current + val screenModel = rememberScreenModel { MoreScreenModel() } + val downloadQueueState by screenModel.downloadQueueState.collectAsState() + MoreScreen( + downloadQueueStateProvider = { downloadQueueState }, + downloadedOnly = screenModel.downloadedOnly, + onDownloadedOnlyChange = { screenModel.downloadedOnly = it }, + incognitoMode = screenModel.incognitoMode, + onIncognitoModeChange = { screenModel.incognitoMode = it }, + isFDroid = context.isInstalledFromFDroid(), + onClickDownloadQueue = { router.pushController(DownloadController()) }, + onClickCategories = { router.pushController(CategoryController()) }, + onClickBackupAndRestore = { router.pushController(SettingsMainController.toBackupScreen()) }, + onClickSettings = { router.pushController(SettingsMainController()) }, + onClickAbout = { router.pushController(SettingsMainController.toAboutScreen()) }, + ) + } +} + +private class MoreScreenModel( + private val downloadManager: DownloadManager = Injekt.get(), + preferences: BasePreferences = Injekt.get(), +) : ScreenModel { + + var downloadedOnly by preferences.downloadedOnly().asState(coroutineScope) + var incognitoMode by preferences.incognitoMode().asState(coroutineScope) + + private var _state: MutableStateFlow = MutableStateFlow(DownloadQueueState.Stopped) + val downloadQueueState: StateFlow = _state.asStateFlow() + + init { + // Handle running/paused status change and queue progress updating + coroutineScope.launchIO { + combine( + DownloadService.isRunning, + downloadManager.queue.updatedFlow(), + ) { isRunning, downloadQueue -> Pair(isRunning, downloadQueue.size) } + .collectLatest { (isDownloading, downloadQueueSize) -> + val pendingDownloadExists = downloadQueueSize != 0 + _state.value = when { + !pendingDownloadExists -> DownloadQueueState.Stopped + !isDownloading && !pendingDownloadExists -> DownloadQueueState.Paused(0) + !isDownloading && pendingDownloadExists -> DownloadQueueState.Paused(downloadQueueSize) + else -> DownloadQueueState.Downloading(downloadQueueSize) + } + } + } + } +} + +sealed class DownloadQueueState { + object Stopped : DownloadQueueState() + data class Paused(val pending: Int) : DownloadQueueState() + data class Downloading(val pending: Int) : DownloadQueueState() +}