Voyager on More tab (#8498)

This commit is contained in:
Ivan Iskandar 2022-11-11 10:08:18 +07:00 committed by GitHub
parent 11ed47397d
commit 340357d158
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 109 additions and 88 deletions

View File

@ -14,8 +14,6 @@ import androidx.compose.material.icons.outlined.Label
import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.SettingsBackupRestore import androidx.compose.material.icons.outlined.SettingsBackupRestore
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalUriHandler 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.R
import eu.kanade.tachiyomi.ui.more.DownloadQueueState import eu.kanade.tachiyomi.ui.more.DownloadQueueState
import eu.kanade.tachiyomi.ui.more.MoreController import eu.kanade.tachiyomi.ui.more.MoreController
import eu.kanade.tachiyomi.ui.more.MorePresenter
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
@Composable @Composable
fun MoreScreen( fun MoreScreen(
presenter: MorePresenter, downloadQueueStateProvider: () -> DownloadQueueState,
downloadedOnly: Boolean,
onDownloadedOnlyChange: (Boolean) -> Unit,
incognitoMode: Boolean,
onIncognitoModeChange: (Boolean) -> Unit,
isFDroid: Boolean, isFDroid: Boolean,
onClickDownloadQueue: () -> Unit, onClickDownloadQueue: () -> Unit,
onClickCategories: () -> Unit, onClickCategories: () -> Unit,
@ -45,7 +46,6 @@ fun MoreScreen(
onClickAbout: () -> Unit, onClickAbout: () -> Unit,
) { ) {
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val downloadQueueState by presenter.downloadQueueState.collectAsState()
ScrollbarLazyColumn( ScrollbarLazyColumn(
modifier = Modifier.statusBarsPadding(), modifier = Modifier.statusBarsPadding(),
@ -70,8 +70,8 @@ fun MoreScreen(
item { item {
AppStateBanners( AppStateBanners(
downloadedOnlyMode = presenter.downloadedOnly.value, downloadedOnlyMode = downloadedOnly,
incognitoMode = presenter.incognitoMode.value, incognitoMode = incognitoMode,
) )
} }
@ -80,8 +80,8 @@ fun MoreScreen(
title = stringResource(R.string.label_downloaded_only), title = stringResource(R.string.label_downloaded_only),
subtitle = stringResource(R.string.downloaded_only_summary), subtitle = stringResource(R.string.downloaded_only_summary),
icon = Icons.Outlined.CloudOff, icon = Icons.Outlined.CloudOff,
checked = presenter.downloadedOnly.value, checked = downloadedOnly,
onCheckedChanged = { presenter.downloadedOnly.value = it }, onCheckedChanged = onDownloadedOnlyChange,
) )
} }
item { item {
@ -89,20 +89,21 @@ fun MoreScreen(
title = stringResource(R.string.pref_incognito_mode), title = stringResource(R.string.pref_incognito_mode),
subtitle = stringResource(R.string.pref_incognito_mode_summary), subtitle = stringResource(R.string.pref_incognito_mode_summary),
icon = ImageVector.vectorResource(R.drawable.ic_glasses_24dp), icon = ImageVector.vectorResource(R.drawable.ic_glasses_24dp),
checked = presenter.incognitoMode.value, checked = incognitoMode,
onCheckedChanged = { presenter.incognitoMode.value = it }, onCheckedChanged = onIncognitoModeChange,
) )
} }
item { Divider() } item { Divider() }
item { item {
val downloadQueueState = downloadQueueStateProvider()
TextPreferenceWidget( TextPreferenceWidget(
title = stringResource(R.string.label_download_queue), title = stringResource(R.string.label_download_queue),
subtitle = when (downloadQueueState) { subtitle = when (downloadQueueState) {
DownloadQueueState.Stopped -> null DownloadQueueState.Stopped -> null
is DownloadQueueState.Paused -> { is DownloadQueueState.Paused -> {
val pending = (downloadQueueState as DownloadQueueState.Paused).pending val pending = downloadQueueState.pending
if (pending == 0) { if (pending == 0) {
stringResource(R.string.paused) stringResource(R.string.paused)
} else { } else {
@ -116,7 +117,7 @@ fun MoreScreen(
} }
} }
is DownloadQueueState.Downloading -> { is DownloadQueueState.Downloading -> {
val pending = (downloadQueueState as DownloadQueueState.Downloading).pending val pending = downloadQueueState.pending
pluralStringResource(id = R.plurals.download_queue_summary, count = pending, pending) pluralStringResource(id = R.plurals.download_queue_summary, count = pending, pending)
} }
}, },

View File

@ -1,32 +1,15 @@
package eu.kanade.tachiyomi.ui.more package eu.kanade.tachiyomi.ui.more
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import eu.kanade.presentation.more.MoreScreen import cafe.adriel.voyager.navigator.Navigator
import eu.kanade.tachiyomi.ui.base.controller.FullComposeController import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController
import eu.kanade.tachiyomi.ui.base.controller.RootController 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 : class MoreController : BasicFullComposeController(), RootController {
FullComposeController<MorePresenter>(),
RootController {
override fun createPresenter() = MorePresenter()
@Composable @Composable
override fun ComposeContent() { override fun ComposeContent() {
MoreScreen( Navigator(screen = 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()) },
)
} }
companion object { companion object {

View File

@ -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<MoreController>() {
val downloadedOnly = preferences.downloadedOnly().asState()
val incognitoMode = preferences.incognitoMode().asState()
private var _state: MutableStateFlow<DownloadQueueState> = MutableStateFlow(DownloadQueueState.Stopped)
val downloadQueueState: StateFlow<DownloadQueueState> = _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()
}

View File

@ -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<DownloadQueueState> = MutableStateFlow(DownloadQueueState.Stopped)
val downloadQueueState: StateFlow<DownloadQueueState> = _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()
}