diff --git a/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt b/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt index 1ec5c15d1a..67f72b85d9 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt @@ -93,8 +93,7 @@ fun UpdateScreen( onMultiBookmarkClicked = presenter::bookmarkUpdates, onMultiMarkAsReadClicked = presenter::markUpdatesRead, onMultiDeleteClicked = { - val updateItems = presenter.selected.map { it.item } - presenter.dialog = Dialog.DeleteConfirmation(updateItems) + presenter.dialog = Dialog.DeleteConfirmation(it) }, ) }, @@ -261,7 +260,7 @@ private fun UpdatesAppBar( @Composable private fun UpdatesBottomBar( - selected: List, + selected: List, onDownloadChapter: (List, ChapterDownloadAction) -> Unit, onMultiBookmarkClicked: (List, bookmark: Boolean) -> Unit, onMultiMarkAsReadClicked: (List, read: Boolean) -> Unit, @@ -271,25 +270,25 @@ private fun UpdatesBottomBar( visible = selected.isNotEmpty(), modifier = Modifier.fillMaxWidth(), onBookmarkClicked = { - onMultiBookmarkClicked.invoke(selected.map { it.item }, true) - }.takeIf { selected.any { !it.item.update.bookmark } }, + onMultiBookmarkClicked.invoke(selected, true) + }.takeIf { selected.any { !it.update.bookmark } }, onRemoveBookmarkClicked = { - onMultiBookmarkClicked.invoke(selected.map { it.item }, false) - }.takeIf { selected.all { it.item.update.bookmark } }, + onMultiBookmarkClicked.invoke(selected, false) + }.takeIf { selected.all { it.update.bookmark } }, onMarkAsReadClicked = { - onMultiMarkAsReadClicked(selected.map { it.item }, true) - }.takeIf { selected.any { !it.item.update.read } }, + onMultiMarkAsReadClicked(selected, true) + }.takeIf { selected.any { !it.update.read } }, onMarkAsUnreadClicked = { - onMultiMarkAsReadClicked(selected.map { it.item }, false) - }.takeIf { selected.any { it.item.update.read } }, + onMultiMarkAsReadClicked(selected, false) + }.takeIf { selected.any { it.update.read } }, onDownloadClicked = { - onDownloadChapter(selected.map { it.item }, ChapterDownloadAction.START) + onDownloadChapter(selected, ChapterDownloadAction.START) }.takeIf { - selected.any { it.item.downloadStateProvider() != Download.State.DOWNLOADED } + selected.any { it.downloadStateProvider() != Download.State.DOWNLOADED } }, onDeleteClicked = { - onMultiDeleteClicked(selected.map { it.item }) - }.takeIf { selected.any { it.item.downloadStateProvider() == Download.State.DOWNLOADED } }, + onMultiDeleteClicked(selected) + }.takeIf { selected.any { it.downloadStateProvider() == Download.State.DOWNLOADED } }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/updates/UpdatesState.kt b/app/src/main/java/eu/kanade/presentation/updates/UpdatesState.kt index fb0ff30511..24b3d64862 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesState.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesState.kt @@ -5,24 +5,47 @@ import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import eu.kanade.core.util.insertSeparators +import eu.kanade.tachiyomi.ui.recent.updates.UpdatesItem import eu.kanade.tachiyomi.ui.recent.updates.UpdatesPresenter +import eu.kanade.tachiyomi.util.lang.toDateKey +import java.util.Date @Stable interface UpdatesState { val isLoading: Boolean - val uiModels: List - val selected: List + val items: List + val selected: List val selectionMode: Boolean + val uiModels: List var dialog: UpdatesPresenter.Dialog? } fun UpdatesState(): UpdatesState = UpdatesStateImpl() class UpdatesStateImpl : UpdatesState { override var isLoading: Boolean by mutableStateOf(true) - override var uiModels: List by mutableStateOf(emptyList()) - override val selected: List by derivedStateOf { - uiModels.filterIsInstance() - .filter { it.item.selected } + override var items: List by mutableStateOf(emptyList()) + override val selected: List by derivedStateOf { + items.filter { it.selected } } override val selectionMode: Boolean by derivedStateOf { selected.isNotEmpty() } + override val uiModels: List by derivedStateOf { + items.toUpdateUiModel() + } override var dialog: UpdatesPresenter.Dialog? by mutableStateOf(null) } + +fun List.toUpdateUiModel(): List { + return this.map { + UpdatesUiModel.Item(it) + } + .insertSeparators { before, after -> + val beforeDate = before?.item?.update?.dateFetch?.toDateKey() ?: Date(0) + val afterDate = after?.item?.update?.dateFetch?.toDateKey() ?: Date(0) + when { + beforeDate.time != afterDate.time && afterDate.time != 0L -> + UpdatesUiModel.Header(afterDate) + // Return null to avoid adding a separator between two items. + else -> null + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt index bbdbf8f200..e243b232ac 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt @@ -4,7 +4,6 @@ import android.os.Bundle import androidx.compose.runtime.Immutable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import eu.kanade.core.util.insertSeparators import eu.kanade.domain.chapter.interactor.GetChapter import eu.kanade.domain.chapter.interactor.SetReadStatus import eu.kanade.domain.chapter.interactor.UpdateChapter @@ -17,7 +16,6 @@ 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 @@ -26,7 +24,6 @@ import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO -import eu.kanade.tachiyomi.util.lang.toDateKey import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.system.logcat import kotlinx.coroutines.Job @@ -87,6 +84,8 @@ class UpdatesPresenter( add(Calendar.MONTH, -3) } + observeDownloads() + getUpdates.subscribe(calendar) .distinctUntilChanged() .catch { @@ -94,15 +93,13 @@ class UpdatesPresenter( _events.send(Event.InternalError) } .collectLatest { updates -> - state.uiModels = updates.toUpdateUiModels() + state.items = updates.toUpdateItems() state.isLoading = false - - observeDownloads() } } } - private fun List.toUpdateUiModels(): List { + private fun List.toUpdateItems(): List { return this.map { update -> val activeDownload = downloadManager.queue.find { update.chapterId == it.chapter.id } val downloaded = downloadManager.isChapterDownloaded( @@ -116,23 +113,12 @@ class UpdatesPresenter( downloaded -> Download.State.DOWNLOADED else -> Download.State.NOT_DOWNLOADED } - val item = UpdatesItem( + UpdatesItem( update = update, downloadStateProvider = { downloadState }, downloadProgressProvider = { activeDownload?.progress ?: 0 }, ) - UpdatesUiModel.Item(item) } - .insertSeparators { before, after -> - val beforeDate = before?.item?.update?.dateFetch?.toDateKey() ?: Date(0) - val afterDate = after?.item?.update?.dateFetch?.toDateKey() ?: Date(0) - when { - beforeDate.time != afterDate.time && afterDate.time != 0L -> - UpdatesUiModel.Header(afterDate) - // Return null to avoid adding a separator between two items. - else -> null - } - } } private suspend fun observeDownloads() { @@ -165,21 +151,18 @@ class UpdatesPresenter( * @param download download object containing progress. */ private fun updateDownloadState(download: Download) { - state.uiModels = uiModels.toMutableList().apply { - val modifiedIndex = uiModels.indexOfFirst { - it is UpdatesUiModel.Item && it.item.update.chapterId == download.chapter.id + state.items = items.toMutableList().apply { + val modifiedIndex = indexOfFirst { + it.update.chapterId == download.chapter.id } if (modifiedIndex < 0) return@apply - var uiModel = removeAt(modifiedIndex) - if (uiModel is UpdatesUiModel.Item) { - val item = uiModel.item.copy( + val item = removeAt(modifiedIndex) + .copy( downloadStateProvider = { download.status }, downloadProgressProvider = { download.progress }, ) - uiModel = UpdatesUiModel.Item(item) - } - add(modifiedIndex, uiModel) + add(modifiedIndex, item) } } @@ -282,24 +265,20 @@ class UpdatesPresenter( downloadManager.deleteChapters(chapters, manga, source).mapNotNull { it.id } } - val deletedUpdates = uiModels.filter { - it is UpdatesUiModel.Item && deletedIds.contains(it.item.update.chapterId) + val deletedUpdates = items.filter { + deletedIds.contains(it.update.chapterId) } if (deletedUpdates.isEmpty()) return@launchNonCancellableIO // TODO: Don't do this fake status update - state.uiModels = uiModels.toMutableList().apply { + state.items = items.toMutableList().apply { deletedUpdates.forEach { deletedUpdate -> val modifiedIndex = indexOf(deletedUpdate) - var uiModel = removeAt(modifiedIndex) - if (uiModel is UpdatesUiModel.Item) { - val item = uiModel.item.copy( - downloadStateProvider = { Download.State.NOT_DOWNLOADED }, - downloadProgressProvider = { 0 }, - ) - uiModel = UpdatesUiModel.Item(item) - } - add(modifiedIndex, uiModel) + val item = removeAt(modifiedIndex).copy( + downloadStateProvider = { Download.State.NOT_DOWNLOADED }, + downloadProgressProvider = { 0 }, + ) + add(modifiedIndex, item) } } } @@ -311,18 +290,16 @@ class UpdatesPresenter( userSelected: Boolean = false, fromLongPress: Boolean = false, ) { - state.uiModels = uiModels.toMutableList().apply { - val modifiedIndex = indexOfFirst { - it is UpdatesUiModel.Item && it.item == item - } + state.items = items.toMutableList().apply { + val modifiedIndex = indexOfFirst { it == item } if (modifiedIndex < 0) return@apply - val oldItem = (get(modifiedIndex) as? UpdatesUiModel.Item)?.item ?: return@apply - if ((oldItem.selected && selected) || (!oldItem.selected && !selected)) return@apply + val oldItem = get(modifiedIndex) + if (oldItem.selected == selected) return@apply - val firstSelection = none { it is UpdatesUiModel.Item && it.item.selected } - var newItem = (removeAt(modifiedIndex) as? UpdatesUiModel.Item)?.item?.copy(selected = selected) ?: return@apply - add(modifiedIndex, UpdatesUiModel.Item(newItem)) + val firstSelection = none { it.selected } + var newItem = removeAt(modifiedIndex).copy(selected = selected) + add(modifiedIndex, newItem) if (selected && userSelected && fromLongPress) { if (firstSelection) { @@ -343,20 +320,16 @@ class UpdatesPresenter( } range.forEach { - var uiModel = removeAt(it) - if (uiModel is UpdatesUiModel.Item) { - newItem = uiModel.item.copy(selected = true) - uiModel = UpdatesUiModel.Item(newItem) - } - add(it, uiModel) + newItem = removeAt(it).copy(selected = true) + add(it, newItem) } } } else if (userSelected && !fromLongPress) { if (!selected) { if (modifiedIndex == selectedPositions[0]) { - selectedPositions[0] = indexOfFirst { it is UpdatesUiModel.Item && it.item.selected } + selectedPositions[0] = indexOfFirst { it.selected } } else if (modifiedIndex == selectedPositions[1]) { - selectedPositions[1] = indexOfLast { it is UpdatesUiModel.Item && it.item.selected } + selectedPositions[1] = indexOfLast { it.selected } } } else { if (modifiedIndex < selectedPositions[0]) { @@ -370,28 +343,16 @@ class UpdatesPresenter( } fun toggleAllSelection(selected: Boolean) { - state.uiModels = state.uiModels.map { - when (it) { - is UpdatesUiModel.Header -> it - is UpdatesUiModel.Item -> { - val newItem = it.item.copy(selected = selected) - UpdatesUiModel.Item(newItem) - } - } + state.items = items.map { + it.copy(selected = selected) } selectedPositions[0] = -1 selectedPositions[1] = -1 } fun invertSelection() { - state.uiModels = state.uiModels.map { - when (it) { - is UpdatesUiModel.Header -> it - is UpdatesUiModel.Item -> { - val newItem = it.item.let { item -> item.copy(selected = !item.selected) } - UpdatesUiModel.Item(newItem) - } - } + state.items = items.map { + it.copy(selected = !it.selected) } selectedPositions[0] = -1 selectedPositions[1] = -1