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.Icon import androidx.compose.material3.IconButton 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.EmptyScreen 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.UpdatesState import kotlinx.coroutines.delay import kotlinx.coroutines.launch import tachiyomi.presentation.core.components.FastScrollLazyColumn import tachiyomi.presentation.core.components.LoadingScreen import tachiyomi.presentation.core.components.material.PullRefresh import tachiyomi.presentation.core.components.material.Scaffold import kotlin.time.Duration.Companion.seconds @Composable fun UpdateScreen( state: UpdatesState, 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 = { IconButton(onClick = onUpdateLibrary) { Icon( imageVector = Icons.Outlined.Refresh, contentDescription = stringResource(R.string.action_update_library), ) } }, actionModeCounter = actionModeCounter, onCancelActionMode = onCancelActionMode, actionModeActions = { IconButton(onClick = onSelectAll) { Icon( imageVector = Icons.Outlined.SelectAll, contentDescription = stringResource(R.string.action_select_all), ) } IconButton(onClick = onInvertSelection) { Icon( imageVector = Icons.Outlined.FlipToBack, contentDescription = stringResource(R.string.action_select_inverse), ) } }, 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 class UpdatesUiModel { data class Header(val date: String) : UpdatesUiModel() data class Item(val item: UpdatesItem) : UpdatesUiModel() }