package eu.kanade.presentation.updates import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.FlipToBack import androidx.compose.material.icons.outlined.Refresh import androidx.compose.material.icons.outlined.SelectAll import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.util.fastAll import androidx.compose.ui.util.fastAny import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBarActions import eu.kanade.presentation.manga.components.ChapterDownloadAction import eu.kanade.presentation.manga.components.MangaBottomActionMenu import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.ui.updates.UpdatesItem import eu.kanade.tachiyomi.ui.updates.UpdatesScreenModel import kotlinx.coroutines.delay import kotlinx.coroutines.launch import tachiyomi.presentation.core.components.FastScrollLazyColumn import tachiyomi.presentation.core.components.material.PullRefresh import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.screens.EmptyScreen import tachiyomi.presentation.core.screens.LoadingScreen import kotlin.time.Duration.Companion.seconds @Composable fun UpdateScreen( state: UpdatesScreenModel.State, snackbarHostState: SnackbarHostState, lastUpdated: Long, relativeTime: Int, onClickCover: (UpdatesItem) -> Unit, onSelectAll: (Boolean) -> Unit, onInvertSelection: () -> Unit, onUpdateLibrary: () -> Boolean, onDownloadChapter: (List, ChapterDownloadAction) -> Unit, onMultiBookmarkClicked: (List, bookmark: Boolean) -> Unit, onMultiMarkAsReadClicked: (List, read: Boolean) -> Unit, onMultiDeleteClicked: (List) -> Unit, onUpdateSelected: (UpdatesItem, Boolean, Boolean, Boolean) -> Unit, onOpenChapter: (UpdatesItem) -> Unit, ) { BackHandler(enabled = state.selectionMode, onBack = { onSelectAll(false) }) val context = LocalContext.current Scaffold( topBar = { scrollBehavior -> UpdatesAppBar( onUpdateLibrary = { onUpdateLibrary() }, actionModeCounter = state.selected.size, onSelectAll = { onSelectAll(true) }, onInvertSelection = { onInvertSelection() }, onCancelActionMode = { onSelectAll(false) }, scrollBehavior = scrollBehavior, ) }, bottomBar = { UpdatesBottomBar( selected = state.selected, onDownloadChapter = onDownloadChapter, onMultiBookmarkClicked = onMultiBookmarkClicked, onMultiMarkAsReadClicked = onMultiMarkAsReadClicked, onMultiDeleteClicked = onMultiDeleteClicked, ) }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, ) { contentPadding -> when { state.isLoading -> LoadingScreen(modifier = Modifier.padding(contentPadding)) state.items.isEmpty() -> EmptyScreen( textResource = R.string.information_no_recent, modifier = Modifier.padding(contentPadding), ) else -> { val scope = rememberCoroutineScope() var isRefreshing by remember { mutableStateOf(false) } PullRefresh( refreshing = isRefreshing, onRefresh = { val started = onUpdateLibrary() if (!started) return@PullRefresh 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) } updatesUiItems( uiModels = state.getUiModel(context, relativeTime), selectionMode = state.selectionMode, onUpdateSelected = onUpdateSelected, onClickCover = onClickCover, onClickUpdate = onOpenChapter, onDownloadChapter = onDownloadChapter, ) } } } } } } @Composable private fun UpdatesAppBar( modifier: Modifier = Modifier, onUpdateLibrary: () -> Unit, // For action mode actionModeCounter: Int, onSelectAll: () -> Unit, onInvertSelection: () -> Unit, onCancelActionMode: () -> Unit, scrollBehavior: TopAppBarScrollBehavior, ) { AppBar( modifier = modifier, title = stringResource(R.string.label_recent_updates), actions = { AppBarActions( listOf( AppBar.Action( title = stringResource(R.string.action_update_library), icon = Icons.Outlined.Refresh, onClick = onUpdateLibrary, ), ), ) }, actionModeCounter = actionModeCounter, onCancelActionMode = onCancelActionMode, actionModeActions = { AppBarActions( listOf( AppBar.Action( title = stringResource(R.string.action_select_all), icon = Icons.Outlined.SelectAll, onClick = onSelectAll, ), AppBar.Action( title = stringResource(R.string.action_select_inverse), icon = Icons.Outlined.FlipToBack, onClick = onInvertSelection, ), ), ) }, scrollBehavior = scrollBehavior, ) } @Composable private fun UpdatesBottomBar( selected: List, onDownloadChapter: (List, ChapterDownloadAction) -> Unit, onMultiBookmarkClicked: (List, bookmark: Boolean) -> Unit, onMultiMarkAsReadClicked: (List, read: Boolean) -> Unit, onMultiDeleteClicked: (List) -> Unit, ) { MangaBottomActionMenu( visible = selected.isNotEmpty(), modifier = Modifier.fillMaxWidth(), onBookmarkClicked = { onMultiBookmarkClicked.invoke(selected, true) }.takeIf { selected.fastAny { !it.update.bookmark } }, onRemoveBookmarkClicked = { onMultiBookmarkClicked.invoke(selected, false) }.takeIf { selected.fastAll { it.update.bookmark } }, onMarkAsReadClicked = { onMultiMarkAsReadClicked(selected, true) }.takeIf { selected.fastAny { !it.update.read } }, onMarkAsUnreadClicked = { onMultiMarkAsReadClicked(selected, false) }.takeIf { selected.fastAny { it.update.read || it.update.lastPageRead > 0L } }, onDownloadClicked = { onDownloadChapter(selected, ChapterDownloadAction.START) }.takeIf { selected.fastAny { it.downloadStateProvider() != Download.State.DOWNLOADED } }, onDeleteClicked = { onMultiDeleteClicked(selected) }.takeIf { selected.fastAny { it.downloadStateProvider() == Download.State.DOWNLOADED } }, ) } sealed interface UpdatesUiModel { data class Header(val date: String) : UpdatesUiModel data class Item(val item: UpdatesItem) : UpdatesUiModel }