Clean up UpdatesController

- Move loading state into scaffold (closes #7704)
- Move logic into presenter
- Make some composables private
This commit is contained in:
arkon 2022-09-18 22:38:44 -04:00
parent f85cbb1582
commit 0e3176a77c
14 changed files with 159 additions and 155 deletions

View file

@ -406,7 +406,7 @@ private fun SourceSwitchPreference(
}
@Composable
fun NsfwWarningDialog(
private fun NsfwWarningDialog(
onClickConfirm: () -> Unit,
) {
AlertDialog(

View file

@ -61,7 +61,7 @@ fun ExtensionFilterScreen(
}
@Composable
fun SourceFilterContent(
private fun SourceFilterContent(
contentPadding: PaddingValues,
state: ExtensionFilterState,
onClickLang: (String) -> Unit,
@ -83,7 +83,7 @@ fun SourceFilterContent(
}
@Composable
fun ExtensionFilterItem(
private fun ExtensionFilterItem(
modifier: Modifier,
lang: String,
enabled: Boolean,

View file

@ -91,7 +91,7 @@ fun ExtensionScreen(
}
@Composable
fun ExtensionContent(
private fun ExtensionContent(
state: ExtensionsState,
onLongClickItem: (Extension) -> Unit,
onClickItemCancel: (Extension) -> Unit,
@ -201,7 +201,7 @@ fun ExtensionContent(
}
@Composable
fun ExtensionItem(
private fun ExtensionItem(
modifier: Modifier = Modifier,
item: ExtensionUiModel.Item,
onClickItem: (Extension) -> Unit,
@ -238,7 +238,7 @@ fun ExtensionItem(
}
@Composable
fun ExtensionItemContent(
private fun ExtensionItemContent(
extension: Extension,
modifier: Modifier = Modifier,
) {
@ -294,7 +294,7 @@ fun ExtensionItemContent(
}
@Composable
fun ExtensionItemActions(
private fun ExtensionItemActions(
extension: Extension,
installStep: InstallStep,
modifier: Modifier = Modifier,
@ -348,7 +348,7 @@ fun ExtensionItemActions(
}
@Composable
fun ExtensionHeader(
private fun ExtensionHeader(
@StringRes textRes: Int,
modifier: Modifier = Modifier,
action: @Composable RowScope.() -> Unit = {},
@ -361,7 +361,7 @@ fun ExtensionHeader(
}
@Composable
fun ExtensionHeader(
private fun ExtensionHeader(
text: String,
modifier: Modifier = Modifier,
action: @Composable RowScope.() -> Unit = {},
@ -382,7 +382,7 @@ fun ExtensionHeader(
}
@Composable
fun ExtensionTrustDialog(
private fun ExtensionTrustDialog(
onClickConfirm: () -> Unit,
onClickDismiss: () -> Unit,
onDismissRequest: () -> Unit,

View file

@ -62,7 +62,7 @@ fun MigrateMangaScreen(
}
@Composable
fun MigrateMangaContent(
private fun MigrateMangaContent(
contentPadding: PaddingValues,
state: MigrateMangaState,
onClickItem: (Manga) -> Unit,
@ -82,7 +82,7 @@ fun MigrateMangaContent(
}
@Composable
fun MigrateMangaItem(
private fun MigrateMangaItem(
modifier: Modifier = Modifier,
manga: Manga,
onClickItem: (Manga) -> Unit,

View file

@ -70,7 +70,7 @@ fun MigrateSourceScreen(
}
@Composable
fun MigrateSourceList(
private fun MigrateSourceList(
list: List<Pair<Source, Long>>,
onClickItem: (Source) -> Unit,
onLongClickItem: (Source) -> Unit,
@ -126,7 +126,7 @@ fun MigrateSourceList(
}
@Composable
fun MigrateSourceItem(
private fun MigrateSourceItem(
modifier: Modifier = Modifier,
source: Source,
count: Long,

View file

@ -66,7 +66,7 @@ fun SourcesFilterScreen(
}
@Composable
fun SourcesFilterContent(
private fun SourcesFilterContent(
contentPadding: PaddingValues,
state: SourcesFilterState,
onClickLang: (String) -> Unit,
@ -111,7 +111,7 @@ fun SourcesFilterContent(
}
@Composable
fun SourcesFilterHeader(
private fun SourcesFilterHeader(
modifier: Modifier,
language: String,
enabled: Boolean,
@ -128,7 +128,7 @@ fun SourcesFilterHeader(
}
@Composable
fun SourcesFilterItem(
private fun SourcesFilterItem(
modifier: Modifier,
source: Source,
enabled: Boolean,

View file

@ -75,7 +75,7 @@ fun SourcesScreen(
}
@Composable
fun SourceList(
private fun SourceList(
state: SourcesState,
onClickItem: (Source, String) -> Unit,
onClickDisable: (Source) -> Unit,
@ -135,7 +135,7 @@ fun SourceList(
}
@Composable
fun SourceHeader(
private fun SourceHeader(
modifier: Modifier = Modifier,
language: String,
) {
@ -149,7 +149,7 @@ fun SourceHeader(
}
@Composable
fun SourceItem(
private fun SourceItem(
modifier: Modifier = Modifier,
source: Source,
onClickItem: (Source, String) -> Unit,
@ -181,7 +181,7 @@ fun SourceItem(
}
@Composable
fun SourcePinButton(
private fun SourcePinButton(
isPinned: Boolean,
onClick: () -> Unit,
) {
@ -197,7 +197,7 @@ fun SourcePinButton(
}
@Composable
fun SourceOptionsDialog(
private fun SourceOptionsDialog(
source: Source,
onClickPin: () -> Unit,
onClickDisable: () -> Unit,

View file

@ -30,6 +30,7 @@ import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.ChapterDownloadAction
import eu.kanade.presentation.components.EmptyScreen
import eu.kanade.presentation.components.LazyColumn
import eu.kanade.presentation.components.LoadingScreen
import eu.kanade.presentation.components.MangaBottomActionMenu
import eu.kanade.presentation.components.Scaffold
import eu.kanade.presentation.components.SwipeRefreshIndicator
@ -55,10 +56,7 @@ fun UpdateScreen(
presenter: UpdatesPresenter,
onClickCover: (UpdatesItem) -> Unit,
onBackClicked: () -> Unit,
onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit,
) {
val updatesListState = rememberLazyListState()
val internalOnBackPressed = {
if (presenter.selectionMode) {
presenter.toggleAllSelection(false)
@ -69,7 +67,6 @@ fun UpdateScreen(
BackHandler(onBack = internalOnBackPressed)
val context = LocalContext.current
val onUpdateLibrary = {
val started = LibraryUpdateService.start(context)
context.toast(if (started) R.string.updating_library else R.string.update_already_running)
@ -92,7 +89,7 @@ fun UpdateScreen(
bottomBar = {
UpdatesBottomBar(
selected = presenter.selected,
onDownloadChapter = onDownloadChapter,
onDownloadChapter = presenter::downloadChapters,
onMultiBookmarkClicked = presenter::bookmarkUpdates,
onMultiMarkAsReadClicked = presenter::markUpdatesRead,
onMultiDeleteClicked = {
@ -102,69 +99,93 @@ fun UpdateScreen(
)
},
) { contentPadding ->
// During selection mode bottom nav is not visible
val contentPaddingWithNavBar = contentPadding +
if (presenter.selectionMode) {
PaddingValues()
} else {
bottomNavPaddingValues
}
val scope = rememberCoroutineScope()
var isRefreshing by remember { mutableStateOf(false) }
SwipeRefresh(
state = rememberSwipeRefreshState(isRefreshing = isRefreshing),
onRefresh = {
val started = onUpdateLibrary()
if (!started) return@SwipeRefresh
scope.launch {
// Fake refresh status but hide it after a second as it's a long running task
isRefreshing = true
delay(1000)
isRefreshing = false
}
},
swipeEnabled = presenter.selectionMode.not(),
indicatorPadding = contentPaddingWithNavBar,
indicator = { s, trigger ->
SwipeRefreshIndicator(
state = s,
refreshTriggerDistance = trigger,
when {
presenter.isLoading -> LoadingScreen()
presenter.uiModels.isEmpty() -> EmptyScreen(textResource = R.string.information_no_recent)
else -> {
UpdateScreenContent(
presenter = presenter,
contentPadding = contentPadding,
onUpdateLibrary = onUpdateLibrary,
onClickCover = onClickCover,
)
},
) {
if (presenter.uiModels.isEmpty()) {
EmptyScreen(textResource = R.string.information_no_recent)
} else {
VerticalFastScroller(
listState = updatesListState,
topContentPadding = contentPaddingWithNavBar.calculateTopPadding(),
endContentPadding = contentPaddingWithNavBar.calculateEndPadding(LocalLayoutDirection.current),
) {
LazyColumn(
modifier = Modifier.fillMaxHeight(),
state = updatesListState,
contentPadding = contentPaddingWithNavBar,
) {
if (presenter.lastUpdated > 0L) {
updatesLastUpdatedItem(presenter.lastUpdated)
}
}
}
}
}
updatesUiItems(
uiModels = presenter.uiModels,
selectionMode = presenter.selectionMode,
onUpdateSelected = presenter::toggleSelection,
onClickCover = onClickCover,
onClickUpdate = {
val intent = ReaderActivity.newIntent(context, it.update.mangaId, it.update.chapterId)
context.startActivity(intent)
},
onDownloadChapter = onDownloadChapter,
relativeTime = presenter.relativeTime,
dateFormat = presenter.dateFormat,
)
@Composable
private fun UpdateScreenContent(
presenter: UpdatesPresenter,
contentPadding: PaddingValues,
onUpdateLibrary: () -> Boolean,
onClickCover: (UpdatesItem) -> Unit,
) {
val context = LocalContext.current
val updatesListState = rememberLazyListState()
// During selection mode bottom nav is not visible
val contentPaddingWithNavBar = contentPadding +
if (presenter.selectionMode) {
PaddingValues()
} else {
bottomNavPaddingValues
}
val scope = rememberCoroutineScope()
var isRefreshing by remember { mutableStateOf(false) }
SwipeRefresh(
state = rememberSwipeRefreshState(isRefreshing = isRefreshing),
onRefresh = {
val started = onUpdateLibrary()
if (!started) return@SwipeRefresh
scope.launch {
// Fake refresh status but hide it after a second as it's a long running task
isRefreshing = true
delay(1000)
isRefreshing = false
}
},
swipeEnabled = presenter.selectionMode.not(),
indicatorPadding = contentPaddingWithNavBar,
indicator = { s, trigger ->
SwipeRefreshIndicator(
state = s,
refreshTriggerDistance = trigger,
)
},
) {
if (presenter.uiModels.isEmpty()) {
EmptyScreen(textResource = R.string.information_no_recent)
} else {
VerticalFastScroller(
listState = updatesListState,
topContentPadding = contentPaddingWithNavBar.calculateTopPadding(),
endContentPadding = contentPaddingWithNavBar.calculateEndPadding(LocalLayoutDirection.current),
) {
LazyColumn(
modifier = Modifier.fillMaxHeight(),
state = updatesListState,
contentPadding = contentPaddingWithNavBar,
) {
if (presenter.lastUpdated > 0L) {
updatesLastUpdatedItem(presenter.lastUpdated)
}
updatesUiItems(
uiModels = presenter.uiModels,
selectionMode = presenter.selectionMode,
onUpdateSelected = presenter::toggleSelection,
onClickCover = onClickCover,
onClickUpdate = {
val intent = ReaderActivity.newIntent(context, it.update.mangaId, it.update.chapterId)
context.startActivity(intent)
},
onDownloadChapter = presenter::downloadChapters,
relativeTime = presenter.relativeTime,
dateFormat = presenter.dateFormat,
)
}
}
}
@ -193,7 +214,7 @@ fun UpdateScreen(
}
@Composable
fun UpdatesAppBar(
private fun UpdatesAppBar(
modifier: Modifier = Modifier,
incognitoMode: Boolean,
downloadedOnlyMode: Boolean,
@ -239,7 +260,7 @@ fun UpdatesAppBar(
}
@Composable
fun UpdatesBottomBar(
private fun UpdatesBottomBar(
selected: List<UpdatesUiModel.Item>,
onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit,
onMultiBookmarkClicked: (List<UpdatesItem>, bookmark: Boolean) -> Unit,

View file

@ -30,7 +30,7 @@ import eu.kanade.tachiyomi.util.system.setDefaultSettings
@Composable
fun WebViewScreen(
onUp: () -> Unit,
onNavigateUp: () -> Unit,
initialTitle: String?,
url: String,
headers: Map<String, String> = emptyMap(),
@ -47,7 +47,7 @@ fun WebViewScreen(
AppBar(
title = state.pageTitle ?: initialTitle,
subtitle = state.content.getCurrentUrl(),
navigateUp = onUp,
navigateUp = onNavigateUp,
navigationIcon = Icons.Default.Close,
actions = {
AppBarActions(

View file

@ -95,14 +95,13 @@ class LibraryController(
}
LaunchedEffect(presenter.selectionMode) {
val activity = (activity as? MainActivity) ?: return@LaunchedEffect
// Could perhaps be removed when navigation is in a Compose world
if (router.backstackSize == 1) {
activity.showBottomNav(presenter.selectionMode.not())
(activity as? MainActivity)?.showBottomNav(presenter.selectionMode.not())
}
}
LaunchedEffect(presenter.isLoading) {
if (presenter.isLoading.not()) {
if (!presenter.isLoading) {
(activity as? MainActivity)?.ready = true
}
}

View file

@ -195,7 +195,7 @@ class MangaController : FullComposeController<MangaPresenter> {
}
}
// Let compose view handle this
// Let Compose view handle this
override fun handleBack(): Boolean {
val dispatcher = (activity as? OnBackPressedDispatcherOwner)?.onBackPressedDispatcher ?: return false
return if (dispatcher.hasEnabledCallbacks()) {

View file

@ -1,24 +1,15 @@
package eu.kanade.tachiyomi.ui.recent.updates
import androidx.activity.OnBackPressedDispatcherOwner
import androidx.compose.animation.Crossfade
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import eu.kanade.presentation.components.ChapterDownloadAction
import eu.kanade.presentation.components.LoadingScreen
import eu.kanade.presentation.updates.UpdateScreen
import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.ui.base.controller.FullComposeController
import eu.kanade.tachiyomi.ui.base.controller.RootController
import eu.kanade.tachiyomi.ui.base.controller.pushController
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController
import kotlinx.coroutines.launch
/**
* Fragment that shows recent chapters.
*/
class UpdatesController :
FullComposeController<UpdatesPresenter>(),
RootController {
@ -27,32 +18,26 @@ class UpdatesController :
@Composable
override fun ComposeContent() {
Crossfade(targetState = presenter.isLoading) { isLoading ->
if (isLoading) {
LoadingScreen()
} else {
UpdateScreen(
presenter = presenter,
onClickCover = { item ->
router.pushController(MangaController(item.update.mangaId))
},
onBackClicked = this::onBackClicked,
onDownloadChapter = this::downloadChapters,
)
}
}
UpdateScreen(
presenter = presenter,
onClickCover = { item ->
router.pushController(MangaController(item.update.mangaId))
},
onBackClicked = {
(activity as? MainActivity)?.moveToStartScreen()
},
)
LaunchedEffect(presenter.selectionMode) {
val activity = (activity as? MainActivity) ?: return@LaunchedEffect
activity.showBottomNav(presenter.selectionMode.not())
(activity as? MainActivity)?.showBottomNav(presenter.selectionMode.not())
}
LaunchedEffect(presenter.isLoading) {
if (presenter.isLoading.not()) {
if (!presenter.isLoading) {
(activity as? MainActivity)?.ready = true
}
}
}
// Let compose view handle this
// Let Compose view handle this
override fun handleBack(): Boolean {
val dispatcher = (activity as? OnBackPressedDispatcherOwner)?.onBackPressedDispatcher ?: return false
return if (dispatcher.hasEnabledCallbacks()) {
@ -62,34 +47,4 @@ class UpdatesController :
false
}
}
private fun onBackClicked() {
(activity as? MainActivity)?.moveToStartScreen()
}
private fun downloadChapters(items: List<UpdatesItem>, action: ChapterDownloadAction) {
if (items.isEmpty()) return
viewScope.launch {
when (action) {
ChapterDownloadAction.START -> {
presenter.downloadChapters(items)
if (items.any { it.downloadStateProvider() == Download.State.ERROR }) {
DownloadService.start(activity!!)
}
}
ChapterDownloadAction.START_NOW -> {
val chapterId = items.singleOrNull()?.update?.chapterId ?: return@launch
presenter.startDownloadingNow(chapterId)
}
ChapterDownloadAction.CANCEL -> {
val chapterId = items.singleOrNull()?.update?.chapterId ?: return@launch
presenter.cancelDownload(chapterId)
}
ChapterDownloadAction.DELETE -> {
presenter.deleteChapters(items)
}
}
presenter.toggleAllSelection(false)
}
}
}

View file

@ -13,10 +13,12 @@ import eu.kanade.domain.chapter.model.toDbChapter
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.updates.interactor.GetUpdates
import eu.kanade.domain.updates.model.UpdatesWithRelations
import eu.kanade.presentation.components.ChapterDownloadAction
import eu.kanade.presentation.updates.UpdatesState
import eu.kanade.presentation.updates.UpdatesStateImpl
import eu.kanade.presentation.updates.UpdatesUiModel
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.SourceManager
@ -33,6 +35,7 @@ import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import logcat.LogPriority
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -178,11 +181,37 @@ class UpdatesPresenter(
}
}
fun startDownloadingNow(chapterId: Long) {
fun downloadChapters(items: List<UpdatesItem>, action: ChapterDownloadAction) {
if (items.isEmpty()) return
presenterScope.launch {
when (action) {
ChapterDownloadAction.START -> {
downloadChapters(items)
if (items.any { it.downloadStateProvider() == Download.State.ERROR }) {
DownloadService.start(view!!.activity!!)
}
}
ChapterDownloadAction.START_NOW -> {
val chapterId = items.singleOrNull()?.update?.chapterId ?: return@launch
startDownloadingNow(chapterId)
}
ChapterDownloadAction.CANCEL -> {
val chapterId = items.singleOrNull()?.update?.chapterId ?: return@launch
cancelDownload(chapterId)
}
ChapterDownloadAction.DELETE -> {
deleteChapters(items)
}
}
toggleAllSelection(false)
}
}
private fun startDownloadingNow(chapterId: Long) {
downloadManager.startDownloadNow(chapterId)
}
fun cancelDownload(chapterId: Long) {
private fun cancelDownload(chapterId: Long) {
val activeDownload = downloadManager.queue.find { chapterId == it.chapter.id } ?: return
downloadManager.deletePendingDownload(activeDownload)
updateDownloadState(activeDownload.apply { status = Download.State.NOT_DOWNLOADED })

View file

@ -45,7 +45,7 @@ class WebViewActivity : BaseActivity() {
setComposeContent {
WebViewScreen(
onUp = { finish() },
onNavigateUp = { finish() },
initialTitle = intent.extras?.getString(TITLE_KEY),
url = url,
headers = headers,