diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Flow.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Flow.kt index 923837b19..582420103 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Flow.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Flow.kt @@ -21,7 +21,6 @@ import kotlinx.coroutines.flow.transform import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.transformWhile import kotlinx.coroutines.flow.update -import kotlinx.coroutines.withTimeout import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.suspendlazy.SuspendLazy import java.util.concurrent.TimeUnit @@ -135,6 +134,28 @@ fun combine( ) } +@Suppress("UNCHECKED_CAST") +fun combine( + flow: Flow, + flow2: Flow, + flow3: Flow, + flow4: Flow, + flow5: Flow, + flow6: Flow, + flow7: Flow, + transform: suspend (T1, T2, T3, T4, T5, T6, T7) -> R, +): Flow = combine(flow, flow2, flow3, flow4, flow5, flow6, flow7) { args: Array<*> -> + transform( + args[0] as T1, + args[1] as T2, + args[2] as T3, + args[3] as T4, + args[4] as T5, + args[5] as T6, + args[6] as T7, + ) +} + suspend fun Flow.firstNotNull(): T = checkNotNull(first { x -> x != null }) suspend fun Flow.firstNotNullOrNull(): T? = firstOrNull { x -> x != null } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/data/MangaDetails.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/data/MangaDetails.kt index c9b3abe62..314bf33f1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/data/MangaDetails.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/data/MangaDetails.kt @@ -17,7 +17,6 @@ data class MangaDetails( private val localManga: LocalManga?, private val override: MangaOverride?, val description: CharSequence?, - @Deprecated("Caller should decide if manga is loaded enough by itself") val isLoaded: Boolean, ) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersMapper.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersMapper.kt index 5042f95fa..b05ff1568 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersMapper.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersMapper.kt @@ -16,6 +16,7 @@ fun MangaDetails.mapChapters( branch: String?, bookmarks: List, isGrid: Boolean, + isDownloadedOnly: Boolean, ): List { val remoteChapters = chapters[branch].orEmpty() val localChapters = local?.manga?.getChapters(branch).orEmpty() @@ -35,19 +36,21 @@ fun MangaDetails.mapChapters( null } var isUnread = currentChapterId !in ids - for (chapter in remoteChapters) { - val local = localMap?.remove(chapter.id) - if (chapter.id == currentChapterId) { - isUnread = true + if (!isDownloadedOnly || local?.manga?.chapters == null) { + for (chapter in remoteChapters) { + val local = localMap?.remove(chapter.id) + if (chapter.id == currentChapterId) { + isUnread = true + } + result += (local ?: chapter).toListItem( + isCurrent = chapter.id == currentChapterId, + isUnread = isUnread, + isNew = isUnread && result.size >= newFrom, + isDownloaded = local != null, + isBookmarked = chapter.id in bookmarked, + isGrid = isGrid, + ) } - result += (local ?: chapter).toListItem( - isCurrent = chapter.id == currentChapterId, - isUnread = isUnread, - isNew = isUnread && result.size >= newFrom, - isDownloaded = local != null, - isBookmarked = chapter.id in bookmarked, - isGrid = isGrid, - ) } if (!localMap.isNullOrEmpty()) { for (chapter in localMap.values) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChapterPagesMenuProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChapterPagesMenuProvider.kt index 6db0ec2b5..fb5227cc1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChapterPagesMenuProvider.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChapterPagesMenuProvider.kt @@ -9,6 +9,7 @@ import androidx.core.view.MenuProvider import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.slider.LabelFormatter import com.google.android.material.slider.Slider +import com.google.android.material.slider.TickVisibilityMode import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet @@ -41,6 +42,10 @@ class ChapterPagesMenuProvider( menu.findItem(R.id.action_search)?.isVisible = viewModel.isChaptersEmpty.value == false menu.findItem(R.id.action_reversed)?.isChecked = viewModel.isChaptersReversed.value == true menu.findItem(R.id.action_grid_view)?.isChecked = viewModel.isChaptersInGridView.value == true + menu.findItem(R.id.action_downloaded)?.let { menuItem -> + menuItem.isVisible = viewModel.mangaDetails.value?.local != null + menuItem.isChecked = viewModel.isDownloadedOnly.value == true + } } TAB_PAGES, TAB_BOOKMARKS -> { @@ -64,6 +69,11 @@ class ChapterPagesMenuProvider( true } + R.id.action_downloaded -> { + viewModel.isDownloadedOnly.value = !menuItem.isChecked + true + } + else -> false } @@ -110,7 +120,7 @@ class ChapterPagesMenuProvider( valueFrom = 50f valueTo = 150f stepSize = 5f - isTickVisible = false + tickVisibilityMode = TickVisibilityMode.TICK_VISIBILITY_HIDDEN labelBehavior = LabelFormatter.LABEL_FLOATING setLabelFormatter(IntPercentLabelFormatter(context)) setValueRounded(settings.gridSizePages.toFloat()) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesSheet.kt index 3e91e7e16..f76f0bd01 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesSheet.kt @@ -81,6 +81,7 @@ class ChaptersPagesSheet : BaseAdaptiveSheet(), val menuInvalidator = MenuInvalidator(binding.toolbar) viewModel.isChaptersReversed.observe(viewLifecycleOwner, menuInvalidator) viewModel.isChaptersInGridView.observe(viewLifecycleOwner, menuInvalidator) + viewModel.isDownloadedOnly.observe(viewLifecycleOwner, menuInvalidator) actionModeDelegate?.addListener(this, viewLifecycleOwner) addSheetCallback(this, viewLifecycleOwner) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt index 88b743d79..2c0f7a467 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt @@ -87,6 +87,8 @@ abstract class ChaptersPagesViewModel( valueProducer = { isChaptersGridView }, ) + val isDownloadedOnly = MutableStateFlow(false) + val newChaptersCount = mangaDetails.flatMapLatest { d -> if (d?.isLocal == false) { interactor.observeNewChapters(d.id) @@ -115,13 +117,15 @@ abstract class ChaptersPagesViewModel( newChaptersCount, bookmarks, isChaptersInGridView, - ) { manga, currentChapterId, branch, news, bookmarks, grid -> + isDownloadedOnly, + ) { manga, currentChapterId, branch, news, bookmarks, grid, downloadedOnly -> manga?.mapChapters( - currentChapterId, - news, - branch, - bookmarks, - grid, + currentChapterId = currentChapterId, + newCount = news, + branch = branch, + bookmarks = bookmarks, + isGrid = grid, + isDownloadedOnly = downloadedOnly, ).orEmpty() }, isChaptersReversed, diff --git a/app/src/main/res/menu/opt_chapters.xml b/app/src/main/res/menu/opt_chapters.xml index 8fee83bac..15ecba0e1 100644 --- a/app/src/main/res/menu/opt_chapters.xml +++ b/app/src/main/res/menu/opt_chapters.xml @@ -11,6 +11,13 @@ app:actionViewClass="androidx.appcompat.widget.SearchView" app:showAsAction="ifRoom|collapseActionView" /> + +