Use Voyager on Updates tab (#8603)

* Use Voyager on Updates tab

* Fix back press

* Fix selection
This commit is contained in:
Ivan Iskandar
2022-11-23 21:22:20 +07:00
committed by GitHub
parent 7d34ff214c
commit acc2312384
9 changed files with 372 additions and 349 deletions
@@ -1,7 +1,6 @@
package eu.kanade.presentation.updates
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
@@ -10,9 +9,11 @@ import androidx.compose.material.icons.outlined.Refresh
import androidx.compose.material.icons.outlined.SelectAll
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ScaffoldDefaults
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -33,152 +34,103 @@ import eu.kanade.presentation.components.Scaffold
import eu.kanade.presentation.components.SwipeRefresh
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.updates.UpdatesItem
import eu.kanade.tachiyomi.ui.updates.UpdatesPresenter
import eu.kanade.tachiyomi.ui.updates.UpdatesPresenter.Dialog
import eu.kanade.tachiyomi.ui.updates.UpdatesPresenter.Event
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.ui.updates.UpdatesState
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import java.util.Date
import kotlin.time.Duration.Companion.seconds
@Composable
fun UpdateScreen(
presenter: UpdatesPresenter,
state: UpdatesState,
snackbarHostState: SnackbarHostState,
incognitoMode: Boolean,
downloadedOnlyMode: Boolean,
lastUpdated: Long,
relativeTime: Int,
onClickCover: (UpdatesItem) -> Unit,
onBackClicked: () -> Unit,
onSelectAll: (Boolean) -> Unit,
onInvertSelection: () -> Unit,
onUpdateLibrary: () -> Boolean,
onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit,
onMultiBookmarkClicked: (List<UpdatesItem>, bookmark: Boolean) -> Unit,
onMultiMarkAsReadClicked: (List<UpdatesItem>, read: Boolean) -> Unit,
onMultiDeleteClicked: (List<UpdatesItem>) -> Unit,
onUpdateSelected: (UpdatesItem, Boolean, Boolean, Boolean) -> Unit,
onOpenChapter: (UpdatesItem) -> Unit,
) {
val internalOnBackPressed = {
if (presenter.selectionMode) {
presenter.toggleAllSelection(false)
} else {
onBackClicked()
}
}
BackHandler(onBack = internalOnBackPressed)
BackHandler(enabled = state.selectionMode, onBack = { onSelectAll(false) })
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)
started
}
Scaffold(
topBar = { scrollBehavior ->
UpdatesAppBar(
incognitoMode = presenter.isIncognitoMode,
downloadedOnlyMode = presenter.isDownloadOnly,
incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode,
onUpdateLibrary = { onUpdateLibrary() },
actionModeCounter = presenter.selected.size,
onSelectAll = { presenter.toggleAllSelection(true) },
onInvertSelection = { presenter.invertSelection() },
onCancelActionMode = { presenter.toggleAllSelection(false) },
actionModeCounter = state.selected.size,
onSelectAll = { onSelectAll(true) },
onInvertSelection = { onInvertSelection() },
onCancelActionMode = { onSelectAll(false) },
scrollBehavior = scrollBehavior,
)
},
bottomBar = {
UpdatesBottomBar(
selected = presenter.selected,
onDownloadChapter = presenter::downloadChapters,
onMultiBookmarkClicked = presenter::bookmarkUpdates,
onMultiMarkAsReadClicked = presenter::markUpdatesRead,
onMultiDeleteClicked = {
presenter.dialog = Dialog.DeleteConfirmation(it)
},
selected = state.selected,
onDownloadChapter = onDownloadChapter,
onMultiBookmarkClicked = onMultiBookmarkClicked,
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
onMultiDeleteClicked = onMultiDeleteClicked,
)
},
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
contentWindowInsets = TachiyomiBottomNavigationView.withBottomNavInset(ScaffoldDefaults.contentWindowInsets),
) { contentPadding ->
val contentPaddingWithNavBar = TachiyomiBottomNavigationView.withBottomNavPadding(contentPadding)
when {
presenter.isLoading -> LoadingScreen()
presenter.uiModels.isEmpty() -> EmptyScreen(
state.isLoading -> LoadingScreen(modifier = Modifier.padding(contentPadding))
state.items.isEmpty() -> EmptyScreen(
textResource = R.string.information_no_recent,
modifier = Modifier.padding(contentPaddingWithNavBar),
modifier = Modifier.padding(contentPadding),
)
else -> {
UpdateScreenContent(
presenter = presenter,
contentPadding = contentPaddingWithNavBar,
onUpdateLibrary = onUpdateLibrary,
onClickCover = onClickCover,
)
}
}
}
}
val scope = rememberCoroutineScope()
var isRefreshing by remember { mutableStateOf(false) }
@Composable
private fun UpdateScreenContent(
presenter: UpdatesPresenter,
contentPadding: PaddingValues,
onUpdateLibrary: () -> Boolean,
onClickCover: (UpdatesItem) -> Unit,
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
var isRefreshing by remember { mutableStateOf(false) }
SwipeRefresh(
refreshing = 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(1.seconds)
isRefreshing = false
}
},
enabled = !state.selectionMode,
indicatorPadding = contentPadding,
) {
FastScrollLazyColumn(
contentPadding = contentPadding,
) {
if (lastUpdated > 0L) {
updatesLastUpdatedItem(lastUpdated)
}
SwipeRefresh(
refreshing = 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(1.seconds)
isRefreshing = false
}
},
enabled = presenter.selectionMode.not(),
indicatorPadding = contentPadding,
) {
FastScrollLazyColumn(
contentPadding = contentPadding,
) {
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,
)
}
}
val onDismissDialog = { presenter.dialog = null }
when (val dialog = presenter.dialog) {
is Dialog.DeleteConfirmation -> {
UpdatesDeleteConfirmationDialog(
onDismissRequest = onDismissDialog,
onConfirm = {
presenter.toggleAllSelection(false)
presenter.deleteChapters(dialog.toDelete)
},
)
}
null -> {}
}
LaunchedEffect(Unit) {
presenter.events.collectLatest { event ->
when (event) {
Event.InternalError -> context.toast(R.string.internal_error)
updatesUiItems(
uiModels = state.getUiModel(context, relativeTime),
selectionMode = state.selectionMode,
onUpdateSelected = onUpdateSelected,
onClickCover = onClickCover,
onClickUpdate = onOpenChapter,
onDownloadChapter = onDownloadChapter,
)
}
}
}
}
}
@@ -265,6 +217,6 @@ private fun UpdatesBottomBar(
}
sealed class UpdatesUiModel {
data class Header(val date: Date) : UpdatesUiModel()
data class Header(val date: String) : UpdatesUiModel()
data class Item(val item: UpdatesItem) : UpdatesUiModel()
}