mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
Simplify updates menu code
This commit is contained in:
@@ -29,7 +29,7 @@ class UpdatesScreen : Screen {
|
||||
val readerLauncher = rememberReaderLauncher()
|
||||
UpdatesScreenContent(
|
||||
isLoading = vm.isLoading.collectAsState().value,
|
||||
dateWithUpdates = vm.updates.collectAsState().value,
|
||||
updates = vm.updates.collectAsState().value,
|
||||
loadNextPage = vm::loadNextPage,
|
||||
openChapter = readerLauncher::launch,
|
||||
openManga = { navigator push MangaScreen(it) },
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
|
||||
package ca.gosyer.jui.ui.updates
|
||||
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateMapOf
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import ca.gosyer.jui.domain.chapter.interactor.DeleteChapterDownload
|
||||
import ca.gosyer.jui.domain.chapter.interactor.QueueChapterDownload
|
||||
import ca.gosyer.jui.domain.chapter.interactor.StopChapterDownload
|
||||
@@ -19,22 +15,22 @@ import ca.gosyer.jui.domain.updates.interactor.GetRecentUpdates
|
||||
import ca.gosyer.jui.ui.base.chapter.ChapterDownloadItem
|
||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.jui.uicore.vm.ViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.buffer
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import me.tatarka.inject.annotations.Inject
|
||||
@@ -51,9 +47,8 @@ class UpdatesScreenViewModel @Inject constructor(
|
||||
private val _isLoading = MutableStateFlow(true)
|
||||
val isLoading = _isLoading.asStateFlow()
|
||||
|
||||
private val _updates = mutableStateMapOf<LocalDate, SnapshotStateList<ChapterDownloadItem>>()
|
||||
val updates = snapshotFlow { _updates.toList().sortedByDescending { it.first }.toImmutableList() }
|
||||
.stateIn(scope, SharingStarted.Eagerly, persistentListOf())
|
||||
private val _updates = MutableStateFlow<ImmutableList<UpdatesUI>>(persistentListOf())
|
||||
val updates = _updates.asStateFlow()
|
||||
|
||||
private val currentPage = MutableStateFlow(1)
|
||||
private val hasNextPage = MutableStateFlow(false)
|
||||
@@ -80,7 +75,14 @@ class UpdatesScreenViewModel @Inject constructor(
|
||||
private suspend fun getUpdates(page: Int) {
|
||||
getRecentUpdates.asFlow(page)
|
||||
.onEach { updates ->
|
||||
updates.page
|
||||
val lastUpdateDate = (_updates.value.lastOrNull() as? UpdatesUI.Item)
|
||||
?.let {
|
||||
Instant.fromEpochSeconds(it.chapterDownloadItem.chapter.fetchedAt)
|
||||
.toLocalDateTime(TimeZone.currentSystemDefault())
|
||||
.date
|
||||
.toString()
|
||||
}
|
||||
val items = updates.page
|
||||
.map {
|
||||
ChapterDownloadItem(
|
||||
it.manga,
|
||||
@@ -89,22 +91,28 @@ class UpdatesScreenViewModel @Inject constructor(
|
||||
}
|
||||
.groupBy {
|
||||
Instant.fromEpochSeconds(it.chapter.fetchedAt).toLocalDateTime(TimeZone.currentSystemDefault()).date
|
||||
}.forEach { (date, chapters) ->
|
||||
val list = _updates.getOrPut(date, ::mutableStateListOf)
|
||||
list += chapters
|
||||
list.sortByDescending { it.chapter.fetchedAt }
|
||||
}
|
||||
.entries
|
||||
.sortedByDescending { it.key.toEpochDays() }
|
||||
_updates.value = _updates.value.plus(
|
||||
items
|
||||
.flatMap { (date, updates) ->
|
||||
listOf(UpdatesUI.Header(date.toString())).dropWhile { it.date == lastUpdateDate } +
|
||||
updates
|
||||
.sortedByDescending { it.chapter.fetchedAt }
|
||||
.map { UpdatesUI.Item(it) }
|
||||
}
|
||||
).toImmutableList()
|
||||
|
||||
downloadServiceJob?.cancel()
|
||||
val mangaIds = _updates.values.flatMap { items ->
|
||||
items.mapNotNull { it.manga?.id }
|
||||
val mangaIds = _updates.value.filterIsInstance<UpdatesUI.Item>().mapNotNull {
|
||||
it.chapterDownloadItem.manga?.id
|
||||
}.toSet()
|
||||
downloadServiceJob = DownloadService.registerWatches(mangaIds)
|
||||
.buffer(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||
.onEach { chapters ->
|
||||
_updates.forEach { (_, updates) ->
|
||||
updates.forEach {
|
||||
it.updateFrom(chapters)
|
||||
}
|
||||
_updates.value.filterIsInstance<UpdatesUI.Item>().forEach {
|
||||
it.chapterDownloadItem.updateFrom(chapters)
|
||||
}
|
||||
}
|
||||
.launchIn(scope)
|
||||
@@ -128,26 +136,26 @@ class UpdatesScreenViewModel @Inject constructor(
|
||||
|
||||
fun deleteDownloadedChapter(chapter: Chapter) {
|
||||
scope.launch {
|
||||
_updates
|
||||
.firstNotNullOfOrNull { (_, chapters) ->
|
||||
chapters.find {
|
||||
it.chapter.mangaId == chapter.mangaId &&
|
||||
it.chapter.index == chapter.index
|
||||
}
|
||||
_updates.value
|
||||
.filterIsInstance<UpdatesUI.Item>()
|
||||
.find { (chapterDownloadItem) ->
|
||||
chapterDownloadItem.chapter.mangaId == chapter.mangaId &&
|
||||
chapterDownloadItem.chapter.index == chapter.index
|
||||
}
|
||||
?.chapterDownloadItem
|
||||
?.deleteDownload(deleteChapterDownload)
|
||||
}
|
||||
}
|
||||
|
||||
fun stopDownloadingChapter(chapter: Chapter) {
|
||||
scope.launch {
|
||||
_updates
|
||||
.firstNotNullOfOrNull { (_, chapters) ->
|
||||
chapters.find {
|
||||
it.chapter.mangaId == chapter.mangaId &&
|
||||
it.chapter.index == chapter.index
|
||||
}
|
||||
_updates.value
|
||||
.filterIsInstance<UpdatesUI.Item>()
|
||||
.find { (chapterDownloadItem) ->
|
||||
chapterDownloadItem.chapter.mangaId == chapter.mangaId &&
|
||||
chapterDownloadItem.chapter.index == chapter.index
|
||||
}
|
||||
?.chapterDownloadItem
|
||||
?.stopDownloading(stopChapterDownload)
|
||||
}
|
||||
}
|
||||
@@ -156,3 +164,8 @@ class UpdatesScreenViewModel @Inject constructor(
|
||||
private val log = logging()
|
||||
}
|
||||
}
|
||||
|
||||
sealed class UpdatesUI {
|
||||
data class Item(val chapterDownloadItem: ChapterDownloadItem) : UpdatesUI()
|
||||
data class Header(val date: String) : UpdatesUI()
|
||||
}
|
||||
@@ -28,7 +28,6 @@ import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
@@ -41,6 +40,7 @@ import ca.gosyer.jui.ui.base.chapter.ChapterDownloadIcon
|
||||
import ca.gosyer.jui.ui.base.chapter.ChapterDownloadItem
|
||||
import ca.gosyer.jui.ui.base.navigation.Toolbar
|
||||
import ca.gosyer.jui.ui.main.components.bottomNav
|
||||
import ca.gosyer.jui.ui.updates.UpdatesUI
|
||||
import ca.gosyer.jui.uicore.components.LoadingScreen
|
||||
import ca.gosyer.jui.uicore.components.MangaListItem
|
||||
import ca.gosyer.jui.uicore.components.MangaListItemColumn
|
||||
@@ -55,12 +55,11 @@ import ca.gosyer.jui.uicore.insets.navigationBars
|
||||
import ca.gosyer.jui.uicore.insets.statusBars
|
||||
import ca.gosyer.jui.uicore.resources.stringResource
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.datetime.LocalDate
|
||||
|
||||
@Composable
|
||||
fun UpdatesScreenContent(
|
||||
isLoading: Boolean,
|
||||
dateWithUpdates: ImmutableList<Pair<LocalDate, SnapshotStateList<ChapterDownloadItem>>>,
|
||||
updates: ImmutableList<UpdatesUI>,
|
||||
loadNextPage: () -> Unit,
|
||||
openChapter: (Int, Long) -> Unit,
|
||||
openManga: (Long) -> Unit,
|
||||
@@ -78,7 +77,7 @@ fun UpdatesScreenContent(
|
||||
Toolbar(stringResource(MR.strings.location_updates))
|
||||
}
|
||||
) {
|
||||
if (isLoading || dateWithUpdates.isEmpty()) {
|
||||
if (isLoading || updates.isEmpty()) {
|
||||
LoadingScreen(isLoading)
|
||||
} else {
|
||||
Box(Modifier.padding(it)) {
|
||||
@@ -92,31 +91,32 @@ fun UpdatesScreenContent(
|
||||
)
|
||||
).asPaddingValues()
|
||||
) {
|
||||
dateWithUpdates.forEachIndexed { index, (date, updates) ->
|
||||
item {
|
||||
Text(
|
||||
text = date.toString(),
|
||||
itemsIndexed(updates) { index, item ->
|
||||
LaunchedEffect(Unit) {
|
||||
if (index == updates.lastIndex) {
|
||||
loadNextPage()
|
||||
}
|
||||
}
|
||||
when (item) {
|
||||
is UpdatesUI.Header -> Text(
|
||||
text = item.date,
|
||||
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
itemsIndexed(updates) { itemIndex, item ->
|
||||
LaunchedEffect(Unit) {
|
||||
if (index == dateWithUpdates.lastIndex && itemIndex == updates.lastIndex) {
|
||||
loadNextPage()
|
||||
}
|
||||
is UpdatesUI.Item -> {
|
||||
val manga = item.chapterDownloadItem.manga!!
|
||||
val chapter = item.chapterDownloadItem.chapter
|
||||
UpdatesItem(
|
||||
chapterDownloadItem = item.chapterDownloadItem,
|
||||
onClickItem = { openChapter(chapter.index, chapter.mangaId) },
|
||||
onClickCover = { openManga(manga.id) },
|
||||
onClickDownload = downloadChapter,
|
||||
onClickDeleteDownload = deleteDownloadedChapter,
|
||||
onClickStopDownload = stopDownloadingChapter
|
||||
)
|
||||
}
|
||||
val manga = item.manga!!
|
||||
val chapter = item.chapter
|
||||
UpdatesItem(
|
||||
chapterDownloadItem = item,
|
||||
onClickItem = { openChapter(chapter.index, chapter.mangaId) },
|
||||
onClickCover = { openManga(manga.id) },
|
||||
onClickDownload = downloadChapter,
|
||||
onClickDeleteDownload = deleteDownloadedChapter,
|
||||
onClickStopDownload = stopDownloadingChapter
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
VerticalScrollbar(
|
||||
|
||||
Reference in New Issue
Block a user