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 @Composable
fun NsfwWarningDialog( private fun NsfwWarningDialog(
onClickConfirm: () -> Unit, onClickConfirm: () -> Unit,
) { ) {
AlertDialog( AlertDialog(

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -75,7 +75,7 @@ fun SourcesScreen(
} }
@Composable @Composable
fun SourceList( private fun SourceList(
state: SourcesState, state: SourcesState,
onClickItem: (Source, String) -> Unit, onClickItem: (Source, String) -> Unit,
onClickDisable: (Source) -> Unit, onClickDisable: (Source) -> Unit,
@ -135,7 +135,7 @@ fun SourceList(
} }
@Composable @Composable
fun SourceHeader( private fun SourceHeader(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
language: String, language: String,
) { ) {
@ -149,7 +149,7 @@ fun SourceHeader(
} }
@Composable @Composable
fun SourceItem( private fun SourceItem(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
source: Source, source: Source,
onClickItem: (Source, String) -> Unit, onClickItem: (Source, String) -> Unit,
@ -181,7 +181,7 @@ fun SourceItem(
} }
@Composable @Composable
fun SourcePinButton( private fun SourcePinButton(
isPinned: Boolean, isPinned: Boolean,
onClick: () -> Unit, onClick: () -> Unit,
) { ) {
@ -197,7 +197,7 @@ fun SourcePinButton(
} }
@Composable @Composable
fun SourceOptionsDialog( private fun SourceOptionsDialog(
source: Source, source: Source,
onClickPin: () -> Unit, onClickPin: () -> Unit,
onClickDisable: () -> 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.ChapterDownloadAction
import eu.kanade.presentation.components.EmptyScreen import eu.kanade.presentation.components.EmptyScreen
import eu.kanade.presentation.components.LazyColumn import eu.kanade.presentation.components.LazyColumn
import eu.kanade.presentation.components.LoadingScreen
import eu.kanade.presentation.components.MangaBottomActionMenu import eu.kanade.presentation.components.MangaBottomActionMenu
import eu.kanade.presentation.components.Scaffold import eu.kanade.presentation.components.Scaffold
import eu.kanade.presentation.components.SwipeRefreshIndicator import eu.kanade.presentation.components.SwipeRefreshIndicator
@ -55,10 +56,7 @@ fun UpdateScreen(
presenter: UpdatesPresenter, presenter: UpdatesPresenter,
onClickCover: (UpdatesItem) -> Unit, onClickCover: (UpdatesItem) -> Unit,
onBackClicked: () -> Unit, onBackClicked: () -> Unit,
onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit,
) { ) {
val updatesListState = rememberLazyListState()
val internalOnBackPressed = { val internalOnBackPressed = {
if (presenter.selectionMode) { if (presenter.selectionMode) {
presenter.toggleAllSelection(false) presenter.toggleAllSelection(false)
@ -69,7 +67,6 @@ fun UpdateScreen(
BackHandler(onBack = internalOnBackPressed) BackHandler(onBack = internalOnBackPressed)
val context = LocalContext.current val context = LocalContext.current
val onUpdateLibrary = { val onUpdateLibrary = {
val started = LibraryUpdateService.start(context) val started = LibraryUpdateService.start(context)
context.toast(if (started) R.string.updating_library else R.string.update_already_running) context.toast(if (started) R.string.updating_library else R.string.update_already_running)
@ -92,7 +89,7 @@ fun UpdateScreen(
bottomBar = { bottomBar = {
UpdatesBottomBar( UpdatesBottomBar(
selected = presenter.selected, selected = presenter.selected,
onDownloadChapter = onDownloadChapter, onDownloadChapter = presenter::downloadChapters,
onMultiBookmarkClicked = presenter::bookmarkUpdates, onMultiBookmarkClicked = presenter::bookmarkUpdates,
onMultiMarkAsReadClicked = presenter::markUpdatesRead, onMultiMarkAsReadClicked = presenter::markUpdatesRead,
onMultiDeleteClicked = { onMultiDeleteClicked = {
@ -102,6 +99,31 @@ fun UpdateScreen(
) )
}, },
) { contentPadding -> ) { contentPadding ->
when {
presenter.isLoading -> LoadingScreen()
presenter.uiModels.isEmpty() -> EmptyScreen(textResource = R.string.information_no_recent)
else -> {
UpdateScreenContent(
presenter = presenter,
contentPadding = contentPadding,
onUpdateLibrary = onUpdateLibrary,
onClickCover = onClickCover,
)
}
}
}
}
@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 // During selection mode bottom nav is not visible
val contentPaddingWithNavBar = contentPadding + val contentPaddingWithNavBar = contentPadding +
if (presenter.selectionMode) { if (presenter.selectionMode) {
@ -160,7 +182,7 @@ fun UpdateScreen(
val intent = ReaderActivity.newIntent(context, it.update.mangaId, it.update.chapterId) val intent = ReaderActivity.newIntent(context, it.update.mangaId, it.update.chapterId)
context.startActivity(intent) context.startActivity(intent)
}, },
onDownloadChapter = onDownloadChapter, onDownloadChapter = presenter::downloadChapters,
relativeTime = presenter.relativeTime, relativeTime = presenter.relativeTime,
dateFormat = presenter.dateFormat, dateFormat = presenter.dateFormat,
) )
@ -168,7 +190,6 @@ fun UpdateScreen(
} }
} }
} }
}
val onDismissDialog = { presenter.dialog = null } val onDismissDialog = { presenter.dialog = null }
when (val dialog = presenter.dialog) { when (val dialog = presenter.dialog) {
@ -193,7 +214,7 @@ fun UpdateScreen(
} }
@Composable @Composable
fun UpdatesAppBar( private fun UpdatesAppBar(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
incognitoMode: Boolean, incognitoMode: Boolean,
downloadedOnlyMode: Boolean, downloadedOnlyMode: Boolean,
@ -239,7 +260,7 @@ fun UpdatesAppBar(
} }
@Composable @Composable
fun UpdatesBottomBar( private fun UpdatesBottomBar(
selected: List<UpdatesUiModel.Item>, selected: List<UpdatesUiModel.Item>,
onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit, onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit,
onMultiBookmarkClicked: (List<UpdatesItem>, bookmark: Boolean) -> Unit, onMultiBookmarkClicked: (List<UpdatesItem>, bookmark: Boolean) -> Unit,

View file

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

View file

@ -95,14 +95,13 @@ class LibraryController(
} }
LaunchedEffect(presenter.selectionMode) { LaunchedEffect(presenter.selectionMode) {
val activity = (activity as? MainActivity) ?: return@LaunchedEffect
// Could perhaps be removed when navigation is in a Compose world // Could perhaps be removed when navigation is in a Compose world
if (router.backstackSize == 1) { if (router.backstackSize == 1) {
activity.showBottomNav(presenter.selectionMode.not()) (activity as? MainActivity)?.showBottomNav(presenter.selectionMode.not())
} }
} }
LaunchedEffect(presenter.isLoading) { LaunchedEffect(presenter.isLoading) {
if (presenter.isLoading.not()) { if (!presenter.isLoading) {
(activity as? MainActivity)?.ready = true (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 { override fun handleBack(): Boolean {
val dispatcher = (activity as? OnBackPressedDispatcherOwner)?.onBackPressedDispatcher ?: return false val dispatcher = (activity as? OnBackPressedDispatcherOwner)?.onBackPressedDispatcher ?: return false
return if (dispatcher.hasEnabledCallbacks()) { return if (dispatcher.hasEnabledCallbacks()) {

View file

@ -1,24 +1,15 @@
package eu.kanade.tachiyomi.ui.recent.updates package eu.kanade.tachiyomi.ui.recent.updates
import androidx.activity.OnBackPressedDispatcherOwner import androidx.activity.OnBackPressedDispatcherOwner
import androidx.compose.animation.Crossfade
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect 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.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.FullComposeController
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.base.controller.pushController
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import kotlinx.coroutines.launch
/**
* Fragment that shows recent chapters.
*/
class UpdatesController : class UpdatesController :
FullComposeController<UpdatesPresenter>(), FullComposeController<UpdatesPresenter>(),
RootController { RootController {
@ -27,32 +18,26 @@ class UpdatesController :
@Composable @Composable
override fun ComposeContent() { override fun ComposeContent() {
Crossfade(targetState = presenter.isLoading) { isLoading ->
if (isLoading) {
LoadingScreen()
} else {
UpdateScreen( UpdateScreen(
presenter = presenter, presenter = presenter,
onClickCover = { item -> onClickCover = { item ->
router.pushController(MangaController(item.update.mangaId)) router.pushController(MangaController(item.update.mangaId))
}, },
onBackClicked = this::onBackClicked, onBackClicked = {
onDownloadChapter = this::downloadChapters, (activity as? MainActivity)?.moveToStartScreen()
},
) )
}
}
LaunchedEffect(presenter.selectionMode) { LaunchedEffect(presenter.selectionMode) {
val activity = (activity as? MainActivity) ?: return@LaunchedEffect (activity as? MainActivity)?.showBottomNav(presenter.selectionMode.not())
activity.showBottomNav(presenter.selectionMode.not())
} }
LaunchedEffect(presenter.isLoading) { LaunchedEffect(presenter.isLoading) {
if (presenter.isLoading.not()) { if (!presenter.isLoading) {
(activity as? MainActivity)?.ready = true (activity as? MainActivity)?.ready = true
} }
} }
} }
// Let compose view handle this // Let Compose view handle this
override fun handleBack(): Boolean { override fun handleBack(): Boolean {
val dispatcher = (activity as? OnBackPressedDispatcherOwner)?.onBackPressedDispatcher ?: return false val dispatcher = (activity as? OnBackPressedDispatcherOwner)?.onBackPressedDispatcher ?: return false
return if (dispatcher.hasEnabledCallbacks()) { return if (dispatcher.hasEnabledCallbacks()) {
@ -62,34 +47,4 @@ class UpdatesController :
false 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.manga.interactor.GetManga
import eu.kanade.domain.updates.interactor.GetUpdates import eu.kanade.domain.updates.interactor.GetUpdates
import eu.kanade.domain.updates.model.UpdatesWithRelations import eu.kanade.domain.updates.model.UpdatesWithRelations
import eu.kanade.presentation.components.ChapterDownloadAction
import eu.kanade.presentation.updates.UpdatesState import eu.kanade.presentation.updates.UpdatesState
import eu.kanade.presentation.updates.UpdatesStateImpl import eu.kanade.presentation.updates.UpdatesStateImpl
import eu.kanade.presentation.updates.UpdatesUiModel import eu.kanade.presentation.updates.UpdatesUiModel
import eu.kanade.tachiyomi.data.download.DownloadManager 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.download.model.Download
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
@ -33,6 +35,7 @@ import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import logcat.LogPriority import logcat.LogPriority
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get 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) downloadManager.startDownloadNow(chapterId)
} }
fun cancelDownload(chapterId: Long) { private fun cancelDownload(chapterId: Long) {
val activeDownload = downloadManager.queue.find { chapterId == it.chapter.id } ?: return val activeDownload = downloadManager.queue.find { chapterId == it.chapter.id } ?: return
downloadManager.deletePendingDownload(activeDownload) downloadManager.deletePendingDownload(activeDownload)
updateDownloadState(activeDownload.apply { status = Download.State.NOT_DOWNLOADED }) updateDownloadState(activeDownload.apply { status = Download.State.NOT_DOWNLOADED })

View file

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