diff --git a/app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt b/app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt new file mode 100644 index 000000000..3b759abba --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/chapter/model/ChapterFilter.kt @@ -0,0 +1,93 @@ +package eu.kanade.domain.chapter.model + +import eu.kanade.domain.manga.model.Manga +import eu.kanade.domain.manga.model.TriStateFilter +import eu.kanade.domain.manga.model.isLocal +import eu.kanade.tachiyomi.data.download.DownloadManager +import eu.kanade.tachiyomi.data.download.model.Download +import eu.kanade.tachiyomi.ui.manga.ChapterItem +import eu.kanade.tachiyomi.util.chapter.getChapterSort +import exh.md.utils.MdUtil + +/** + * Applies the view filters to the list of chapters obtained from the database. + * @return an observable of the list of chapters filtered and sorted. + */ +fun List.applyFilters(manga: Manga, downloadManager: DownloadManager): List { + val isLocalManga = manga.isLocal() + val unreadFilter = manga.unreadFilter + val downloadedFilter = manga.downloadedFilter + val bookmarkedFilter = manga.bookmarkedFilter + + return filter { chapter -> + when (unreadFilter) { + TriStateFilter.DISABLED -> true + TriStateFilter.ENABLED_IS -> !chapter.read + TriStateFilter.ENABLED_NOT -> chapter.read + } + } + .filter { chapter -> + when (bookmarkedFilter) { + TriStateFilter.DISABLED -> true + TriStateFilter.ENABLED_IS -> chapter.bookmark + TriStateFilter.ENABLED_NOT -> !chapter.bookmark + } + } + .filter { chapter -> + val downloaded = downloadManager.isChapterDownloaded(chapter.name, chapter.scanlator, manga.title, manga.source) + val downloadState = when { + downloaded -> Download.State.DOWNLOADED + else -> Download.State.NOT_DOWNLOADED + } + when (downloadedFilter) { + TriStateFilter.DISABLED -> true + TriStateFilter.ENABLED_IS -> downloadState == Download.State.DOWNLOADED || isLocalManga + TriStateFilter.ENABLED_NOT -> downloadState != Download.State.DOWNLOADED && !isLocalManga + } + } + // SY --> + .filter { chapter -> + manga.filteredScanlators.isNullOrEmpty() || MdUtil.getScanlators(chapter.scanlator).any { group -> manga.filteredScanlators.contains(group) } + } + // SY <-- + .sortedWith(getChapterSort(manga)) +} + +/** + * Applies the view filters to the list of chapters obtained from the database. + * @return an observable of the list of chapters filtered and sorted. + */ +fun List.applyFilters(manga: Manga): Sequence { + val isLocalManga = manga.isLocal() + val unreadFilter = manga.unreadFilter + val downloadedFilter = manga.downloadedFilter + val bookmarkedFilter = manga.bookmarkedFilter + return asSequence() + .filter { (chapter) -> + when (unreadFilter) { + TriStateFilter.DISABLED -> true + TriStateFilter.ENABLED_IS -> !chapter.read + TriStateFilter.ENABLED_NOT -> chapter.read + } + } + .filter { (chapter) -> + when (bookmarkedFilter) { + TriStateFilter.DISABLED -> true + TriStateFilter.ENABLED_IS -> chapter.bookmark + TriStateFilter.ENABLED_NOT -> !chapter.bookmark + } + } + .filter { + when (downloadedFilter) { + TriStateFilter.DISABLED -> true + TriStateFilter.ENABLED_IS -> it.isDownloaded || isLocalManga + TriStateFilter.ENABLED_NOT -> !it.isDownloaded && !isLocalManga + } + } + // SY --> + .filter { chapter -> + manga.filteredScanlators.isNullOrEmpty() || MdUtil.getScanlators(chapter.chapter.scanlator).any { group -> manga.filteredScanlators.contains(group) } + } + // SY <-- + .sortedWith { (chapter1), (chapter2) -> getChapterSort(manga).invoke(chapter1, chapter2) } +} diff --git a/app/src/main/java/eu/kanade/domain/library/service/LibraryPreferences.kt b/app/src/main/java/eu/kanade/domain/library/service/LibraryPreferences.kt index 703040664..85c62b330 100644 --- a/app/src/main/java/eu/kanade/domain/library/service/LibraryPreferences.kt +++ b/app/src/main/java/eu/kanade/domain/library/service/LibraryPreferences.kt @@ -35,6 +35,8 @@ class LibraryPreferences( fun autoUpdateTrackers() = preferenceStore.getBoolean("auto_update_trackers", false) + fun showContinueReadingButton() = preferenceStore.getBoolean("display_continue_reading_button", false) + // region Filter fun filterDownloaded() = preferenceStore.getInt("pref_filter_library_downloaded", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) @@ -122,8 +124,6 @@ class LibraryPreferences( fun groupLibraryUpdateType() = preferenceStore.getEnum("group_library_update_type", GroupLibraryMode.GLOBAL) - fun startReadingButton() = preferenceStore.getBoolean("start_reading_button", true) - fun groupLibraryBy() = preferenceStore.getInt("group_library_by", LibraryGroup.BY_DEFAULT) // SY <-- diff --git a/app/src/main/java/eu/kanade/presentation/components/CommonMangaItem.kt b/app/src/main/java/eu/kanade/presentation/components/CommonMangaItem.kt index fddadbb11..f18d166f5 100644 --- a/app/src/main/java/eu/kanade/presentation/components/CommonMangaItem.kt +++ b/app/src/main/java/eu/kanade/presentation/components/CommonMangaItem.kt @@ -12,10 +12,17 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material3.FilledIconButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Alignment @@ -41,6 +48,7 @@ object CommonMangaItemDefaults { const val BrowseFavoriteCoverAlpha = 0.34f } +private val ContinueReadingButtonSize = 38.dp private const val GridSelectedCoverAlpha = 0.76f /** @@ -55,12 +63,10 @@ fun MangaCompactGridItem( coverAlpha: Float = 1f, coverBadgeStart: (@Composable RowScope.() -> Unit)? = null, coverBadgeEnd: (@Composable RowScope.() -> Unit)? = null, - // SY --> - buttonTop: (@Composable () -> Unit)? = null, - buttonBottom: (@Composable () -> Unit)? = null, - // SY <-- + showContinueReadingButton: Boolean = false, onLongClick: () -> Unit, onClick: () -> Unit, + onClickContinueReading: (() -> Unit)? = null, ) { GridItemSelectable( isSelected = isSelected, @@ -78,13 +84,14 @@ fun MangaCompactGridItem( }, badgesStart = coverBadgeStart, badgesEnd = coverBadgeEnd, - // SY --> - buttonTop = buttonTop, - buttonBottom = buttonBottom, - // SY <-- content = { if (title != null) { - CoverTextOverlay(title = title) + CoverTextOverlay(title = title, showContinueReadingButton) + } + }, + continueReadingButton = { + if (showContinueReadingButton && onClickContinueReading != null) { + ContinueReadingButton(onClickContinueReading) } }, ) @@ -95,7 +102,10 @@ fun MangaCompactGridItem( * Title overlay for [MangaCompactGridItem] */ @Composable -private fun BoxScope.CoverTextOverlay(title: String) { +private fun BoxScope.CoverTextOverlay( + title: String, + showContinueReadingButton: Boolean = false, +) { Box( modifier = Modifier .clip(RoundedCornerShape(bottomStart = 4.dp, bottomEnd = 4.dp)) @@ -109,9 +119,10 @@ private fun BoxScope.CoverTextOverlay(title: String) { .fillMaxWidth() .align(Alignment.BottomCenter), ) + val endPadding = if (showContinueReadingButton) ContinueReadingButtonSize else 8.dp GridItemTitle( modifier = Modifier - .padding(8.dp) + .padding(start = 8.dp, top = 8.dp, end = endPadding, bottom = 8.dp) .align(Alignment.BottomStart), title = title, style = MaterialTheme.typography.titleSmall.copy( @@ -135,12 +146,10 @@ fun MangaComfortableGridItem( coverAlpha: Float = 1f, coverBadgeStart: (@Composable RowScope.() -> Unit)? = null, coverBadgeEnd: (@Composable RowScope.() -> Unit)? = null, - // SY --> - buttonTop: (@Composable () -> Unit)? = null, - buttonBottom: (@Composable () -> Unit)? = null, - // SY <-- + showContinueReadingButton: Boolean = false, onLongClick: () -> Unit, onClick: () -> Unit, + onClickContinueReading: (() -> Unit)? = null, ) { GridItemSelectable( isSelected = isSelected, @@ -159,10 +168,11 @@ fun MangaComfortableGridItem( }, badgesStart = coverBadgeStart, badgesEnd = coverBadgeEnd, - // SY --> - buttonTop = buttonTop, - buttonBottom = buttonBottom, - // SY <-- + continueReadingButton = { + if (showContinueReadingButton && onClickContinueReading != null) { + ContinueReadingButton(onClickContinueReading) + } + }, ) GridItemTitle( modifier = Modifier.padding(4.dp), @@ -182,10 +192,7 @@ private fun MangaGridCover( cover: @Composable BoxScope.() -> Unit = {}, badgesStart: (@Composable RowScope.() -> Unit)? = null, badgesEnd: (@Composable RowScope.() -> Unit)? = null, - // SY --> - buttonTop: (@Composable () -> Unit)? = null, - buttonBottom: (@Composable () -> Unit)? = null, - // SY <-- + continueReadingButton: (@Composable BoxScope.() -> Unit)? = null, content: @Composable (BoxScope.() -> Unit)? = null, ) { Box( @@ -204,26 +211,15 @@ private fun MangaGridCover( ) } - // SY --> - Column(Modifier.align(Alignment.TopEnd), horizontalAlignment = Alignment.End) { - // SY <-- - if (badgesEnd != null) { - BadgeGroup( - modifier = Modifier - .padding(4.dp), - // SY --> .align(Alignment.TopEnd), SY <-- - content = badgesEnd, - ) - } - // SY --> - buttonTop?.invoke() + if (badgesEnd != null) { + BadgeGroup( + modifier = Modifier + .padding(4.dp) + .align(Alignment.TopEnd), + content = badgesEnd, + ) } - if (buttonBottom != null) { - Box(Modifier.align(Alignment.BottomEnd)) { - buttonBottom() - } - } - // SY <-- + continueReadingButton?.invoke(this) } } @@ -315,8 +311,10 @@ fun MangaListItem( coverData: eu.kanade.domain.manga.model.MangaCover, coverAlpha: Float = 1f, badge: @Composable RowScope.() -> Unit, + showContinueReadingButton: Boolean = false, onLongClick: () -> Unit, onClick: () -> Unit, + onClickContinueReading: (() -> Unit)? = null, ) { Row( modifier = Modifier @@ -345,5 +343,37 @@ fun MangaListItem( style = MaterialTheme.typography.bodyMedium, ) BadgeGroup(content = badge) + if (showContinueReadingButton && onClickContinueReading != null) { + Box { + ContinueReadingButton(onClickContinueReading) + } + } + } +} + +@Composable +private fun BoxScope.ContinueReadingButton( + onClickContinueReading: () -> Unit, +) { + FilledIconButton( + onClick = { + onClickContinueReading() + }, + modifier = Modifier + .size(ContinueReadingButtonSize) + .padding(3.dp) + .align(Alignment.BottomEnd), + shape = MaterialTheme.shapes.small, + colors = IconButtonDefaults.filledIconButtonColors( + containerColor = MaterialTheme.colorScheme.primaryContainer, + contentColor = contentColorFor(MaterialTheme.colorScheme.primaryContainer), + ), + ) { + Icon( + imageVector = Icons.Filled.PlayArrow, + contentDescription = "", + modifier = Modifier + .size(15.dp), + ) } } diff --git a/app/src/main/java/eu/kanade/presentation/library/LibraryScreen.kt b/app/src/main/java/eu/kanade/presentation/library/LibraryScreen.kt index 0d3ca6a52..088224a78 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibraryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibraryScreen.kt @@ -29,6 +29,7 @@ import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView fun LibraryScreen( presenter: LibraryPresenter, onMangaClicked: (Long) -> Unit, + onContinueReadingClicked: (LibraryManga) -> Unit, onGlobalSearchClicked: () -> Unit, onChangeCategoryClicked: () -> Unit, onMarkAsReadClicked: () -> Unit, @@ -46,7 +47,6 @@ fun LibraryScreen( onClickMigrate: () -> Unit, onClickAddToMangaDex: () -> Unit, onClickSyncExh: () -> Unit, - onOpenReader: (LibraryManga) -> Unit, // SY <-- ) { val haptic = LocalHapticFeedback.current @@ -119,6 +119,7 @@ fun LibraryScreen( showMangaCount = presenter.mangaCountVisibility, onChangeCurrentPage = { presenter.activeCategory = it }, onMangaClicked = onMangaClicked, + onContinueReadingClicked = onContinueReadingClicked, onToggleSelection = { presenter.toggleSelection(it) }, onToggleRangeSelection = { presenter.toggleRangeSelection(it) @@ -136,13 +137,10 @@ fun LibraryScreen( showUnreadBadges = presenter.showUnreadBadges, showLocalBadges = presenter.showLocalBadges, showLanguageBadges = presenter.showLanguageBadges, - // SY --> - showStartReadingButton = presenter.showStartReadingButton, - // SY <-- + showContinueReadingButton = presenter.showContinueReadingButton, isIncognitoMode = presenter.isIncognitoMode, isDownloadOnly = presenter.isDownloadOnly, // SY --> - onOpenReader = onOpenReader, getCategoryName = presenter::getCategoryName, // SY <-- ) diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt index b35105cfd..beb9ba51a 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt @@ -18,19 +18,15 @@ fun LibraryComfortableGrid( showUnreadBadges: Boolean, showLocalBadges: Boolean, showLanguageBadges: Boolean, - // SY --> - showStartReadingButton: Boolean, - // SY <-- + showContinueReadingButton: Boolean, columns: Int, contentPadding: PaddingValues, selection: List, onClick: (LibraryManga) -> Unit, onLongClick: (LibraryManga) -> Unit, + onClickContinueReading: (LibraryManga) -> Unit, searchQuery: String?, onGlobalSearchClicked: () -> Unit, - // SY --> - onOpenReader: (LibraryManga) -> Unit, - // SY <-- ) { LazyLibraryGrid( modifier = Modifier.fillMaxSize(), @@ -71,15 +67,10 @@ fun LibraryComfortableGrid( item = libraryItem, ) }, - // SY --> - buttonBottom = if (showStartReadingButton && libraryItem.unreadCount > 0) { - { StartReadingButton(onOpenReader = { onOpenReader(libraryItem.libraryManga) }) } - } else { - null - }, - // SY <-- + showContinueReadingButton = showContinueReadingButton, onLongClick = { onLongClick(libraryItem.libraryManga) }, onClick = { onClick(libraryItem.libraryManga) }, + onClickContinueReading = { onClickContinueReading(libraryItem.libraryManga) }, ) } } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt index e5deee168..6dd62fda3 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt @@ -19,19 +19,15 @@ fun LibraryCompactGrid( showUnreadBadges: Boolean, showLocalBadges: Boolean, showLanguageBadges: Boolean, - // SY --> - showStartReadingButton: Boolean, - // SY <-- + showContinueReadingButton: Boolean, columns: Int, contentPadding: PaddingValues, selection: List, onClick: (LibraryManga) -> Unit, onLongClick: (LibraryManga) -> Unit, + onClickContinueReading: (LibraryManga) -> Unit, searchQuery: String?, onGlobalSearchClicked: () -> Unit, - // SY --> - onOpenReader: (LibraryManga) -> Unit, - // SY <-- ) { LazyLibraryGrid( modifier = Modifier.fillMaxSize(), @@ -72,20 +68,10 @@ fun LibraryCompactGrid( item = libraryItem, ) }, - // SY --> - buttonTop = if (showStartReadingButton && showTitle && libraryItem.unreadCount > 0) { - { StartReadingButton(onOpenReader = { onOpenReader(libraryItem.libraryManga) }) } - } else { - null - }, - buttonBottom = if (showStartReadingButton && !showTitle && libraryItem.unreadCount > 0) { - { StartReadingButton(onOpenReader = { onOpenReader(libraryItem.libraryManga) }) } - } else { - null - }, - // SY <-- + showContinueReadingButton = showContinueReadingButton, onLongClick = { onLongClick(libraryItem.libraryManga) }, onClick = { onClick(libraryItem.libraryManga) }, + onClickContinueReading = { onClickContinueReading(libraryItem.libraryManga) }, ) } } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt index 9e4e54488..8b8a00526 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt @@ -39,6 +39,7 @@ fun LibraryContent( showMangaCount: Boolean, onChangeCurrentPage: (Int) -> Unit, onMangaClicked: (Long) -> Unit, + onContinueReadingClicked: (LibraryManga) -> Unit, onToggleSelection: (LibraryManga) -> Unit, onToggleRangeSelection: (LibraryManga) -> Unit, onRefresh: (Category?) -> Boolean, @@ -51,13 +52,10 @@ fun LibraryContent( showUnreadBadges: Boolean, showLocalBadges: Boolean, showLanguageBadges: Boolean, - // SY --> - showStartReadingButton: Boolean, - // SY <-- + showContinueReadingButton: Boolean, isDownloadOnly: Boolean, isIncognitoMode: Boolean, // SY --> - onOpenReader: (LibraryManga) -> Unit, getCategoryName: (Context, Category, Int, String) -> String, // SY <-- ) { @@ -105,6 +103,9 @@ fun LibraryContent( val onLongClickManga = { manga: LibraryManga -> onToggleRangeSelection(manga) } + val onClickContinueReading = { manga: LibraryManga -> + onContinueReadingClicked(manga) + } SwipeRefresh( refreshing = isRefreshing, @@ -132,16 +133,12 @@ fun LibraryContent( showUnreadBadges = showUnreadBadges, showLocalBadges = showLocalBadges, showLanguageBadges = showLanguageBadges, - // SY --> - showStartReadingButton = showStartReadingButton, - // SY <-- + showContinueReadingButton = showContinueReadingButton, onClickManga = onClickManga, onLongClickManga = onLongClickManga, + onClickContinueReading = onClickContinueReading, onGlobalSearchClicked = onGlobalSearchClicked, searchQuery = state.searchQuery, - // SY --> - onOpenReader = onOpenReader, - // SY <-- ) } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryList.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryList.kt index 97ec5b412..d4f04d453 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryList.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryList.kt @@ -27,10 +27,12 @@ fun LibraryList( showUnreadBadges: Boolean, showLocalBadges: Boolean, showLanguageBadges: Boolean, + showContinueReadingButton: Boolean, contentPadding: PaddingValues, selection: List, onClick: (LibraryManga) -> Unit, onLongClick: (LibraryManga) -> Unit, + onClickContinueReading: (LibraryManga) -> Unit, searchQuery: String?, onGlobalSearchClicked: () -> Unit, ) { @@ -72,8 +74,10 @@ fun LibraryList( UnreadBadge(enabled = showUnreadBadges, item = libraryItem) LanguageBadge(showLanguage = showLanguageBadges, showLocal = showLocalBadges, item = libraryItem) }, + showContinueReadingButton = showContinueReadingButton, onLongClick = { onLongClick(libraryItem.libraryManga) }, onClick = { onClick(libraryItem.libraryManga) }, + onClickContinueReading = { onClickContinueReading(libraryItem.libraryManga) }, ) } } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt index 7188c4d96..40618a689 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt @@ -32,14 +32,10 @@ fun LibraryPager( showUnreadBadges: Boolean, showLocalBadges: Boolean, showLanguageBadges: Boolean, - // SY --> - showStartReadingButton: Boolean, - // SY <-- + showContinueReadingButton: Boolean, onClickManga: (LibraryManga) -> Unit, onLongClickManga: (LibraryManga) -> Unit, - // SY --> - onOpenReader: (LibraryManga) -> Unit, - // SY <-- + onClickContinueReading: (LibraryManga) -> Unit, ) { HorizontalPager( count = pageCount, @@ -70,10 +66,12 @@ fun LibraryPager( showUnreadBadges = showUnreadBadges, showLocalBadges = showLocalBadges, showLanguageBadges = showLanguageBadges, + showContinueReadingButton = showContinueReadingButton, contentPadding = contentPadding, selection = selectedManga, onClick = onClickManga, onLongClick = onLongClickManga, + onClickContinueReading = onClickContinueReading, searchQuery = searchQuery, onGlobalSearchClicked = onGlobalSearchClicked, ) @@ -86,19 +84,15 @@ fun LibraryPager( showUnreadBadges = showUnreadBadges, showLocalBadges = showLocalBadges, showLanguageBadges = showLanguageBadges, - // SY --> - showStartReadingButton = showStartReadingButton, - // SY <-- + showContinueReadingButton = showContinueReadingButton, columns = columns, contentPadding = contentPadding, selection = selectedManga, onClick = onClickManga, onLongClick = onLongClickManga, + onClickContinueReading = onClickContinueReading, searchQuery = searchQuery, onGlobalSearchClicked = onGlobalSearchClicked, - // SY --> - onOpenReader = onOpenReader, - // SY <-- ) } LibraryDisplayMode.ComfortableGrid -> { @@ -108,19 +102,15 @@ fun LibraryPager( showUnreadBadges = showUnreadBadges, showLocalBadges = showLocalBadges, showLanguageBadges = showLanguageBadges, - // SY --> - showStartReadingButton = showStartReadingButton, - // SY <-- + showContinueReadingButton = showContinueReadingButton, columns = columns, contentPadding = contentPadding, selection = selectedManga, onClick = onClickManga, + onClickContinueReading = onClickContinueReading, onLongClick = onLongClickManga, searchQuery = searchQuery, onGlobalSearchClicked = onGlobalSearchClicked, - // SY --> - onOpenReader = onOpenReader, - // SY <-- ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index 33c5d67e7..9d336bc40 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -13,7 +13,9 @@ import com.bluelinelabs.conductor.ControllerChangeType import com.google.android.material.dialog.MaterialAlertDialogBuilder import eu.kanade.core.prefs.CheckboxState import eu.kanade.domain.UnsortedPreferences +import eu.kanade.domain.chapter.model.Chapter import eu.kanade.domain.library.model.LibraryGroup +import eu.kanade.domain.library.model.LibraryManga import eu.kanade.domain.manga.model.Manga import eu.kanade.domain.manga.model.isLocal import eu.kanade.domain.manga.model.toDbManga @@ -35,7 +37,6 @@ import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchUI -import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.system.toast import exh.favorites.FavoritesIntroDialog import exh.favorites.FavoritesSyncStatus @@ -84,6 +85,7 @@ class LibraryController( LibraryScreen( presenter = presenter, onMangaClicked = ::openManga, + onContinueReadingClicked = ::continueReading, onGlobalSearchClicked = { router.pushController(GlobalSearchController(presenter.searchQuery)) }, @@ -140,9 +142,6 @@ class LibraryController( } }, onClickAddToMangaDex = ::pushToMdList, - onOpenReader = { - startReading(it.manga) - }, onClickSyncExh = { // TODO if (Injekt.get().exhShowSyncIntro().get()) { @@ -280,6 +279,19 @@ class LibraryController( router.pushController(MangaController(mangaId)) } + private fun continueReading(libraryManga: LibraryManga) { + viewScope.launchIO { + val chapter = presenter.getNextUnreadChapter(libraryManga.manga) + if (chapter != null) openChapter(chapter) + } + } + + private fun openChapter(chapter: Chapter) { + activity?.run { + startActivity(ReaderActivity.newIntent(this, chapter.mangaId, chapter.id)) + } + } + /** * Clear all of the manga currently selected, and * invalidate the action mode to revert the top toolbar @@ -496,17 +508,5 @@ class LibraryController( favSyncDialog?.setMessage(status.delayedMessage) } } - - private fun startReading(manga: Manga) { - val activity = activity ?: return - viewScope.launchIO { - val chapter = presenter.getFirstUnread(manga) ?: return@launchIO - val intent = ReaderActivity.newIntent(activity, manga.id, chapter.id) - presenter.clearSelection() - withUIContext { - startActivity(intent) - } - } - } // <-- EXH } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 2a8d0c737..245223920 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -20,6 +20,7 @@ import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.category.interactor.GetCategories import eu.kanade.domain.category.interactor.SetMangaCategories import eu.kanade.domain.category.model.Category +import eu.kanade.domain.chapter.interactor.GetChapterByMangaId import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId import eu.kanade.domain.chapter.interactor.SetReadStatus import eu.kanade.domain.chapter.model.Chapter @@ -64,6 +65,7 @@ import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.all.MergedSource import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter +import eu.kanade.tachiyomi.util.chapter.getNextUnread import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.withIOContext @@ -118,9 +120,10 @@ typealias LibraryMap = Map> class LibraryPresenter( private val state: LibraryStateImpl = LibraryState() as LibraryStateImpl, private val getLibraryManga: GetLibraryManga = Injekt.get(), - private val getTracksPerManga: GetTracksPerManga = Injekt.get(), private val getCategories: GetCategories = Injekt.get(), + private val getTracksPerManga: GetTracksPerManga = Injekt.get(), private val getNextChapters: GetNextChapters = Injekt.get(), + private val getChaptersByMangaId: GetChapterByMangaId = Injekt.get(), private val setReadStatus: SetReadStatus = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), private val setMangaCategories: SetMangaCategories = Injekt.get(), @@ -157,12 +160,10 @@ class LibraryPresenter( val showLocalBadges by libraryPreferences.localBadge().asState() val showLanguageBadges by libraryPreferences.languageBadge().asState() - // SY --> - val showStartReadingButton by libraryPreferences.startReadingButton().asState() - // SY <-- - var activeCategory: Int by libraryPreferences.lastUsedCategory().asState() + val showContinueReadingButton by libraryPreferences.showContinueReadingButton().asState() + val isDownloadOnly: Boolean by preferences.downloadedOnly().asState() val isIncognitoMode: Boolean by preferences.incognitoMode().asState() @@ -581,6 +582,10 @@ class LibraryPresenter( .reduce { set1, set2 -> set1.intersect(set2) } } + suspend fun getNextUnreadChapter(manga: Manga): Chapter? { + return getChaptersByMangaId.await(manga.id).getNextUnread(manga, downloadManager) + } + /** * Returns the mix (non-common) categories for the given list of manga. * diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt index e2f76d886..0d4a6373b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt @@ -327,21 +327,15 @@ class LibrarySettingsSheet( private val displayGroup: DisplayGroup private val badgeGroup: BadgeGroup - - // SY --> - private val buttonsGroup: ButtonsGroup - - // SY <-- private val tabsGroup: TabsGroup + private val otherGroup: OtherGroup init { displayGroup = DisplayGroup() badgeGroup = BadgeGroup() - // SY --> - buttonsGroup = ButtonsGroup() - // SY <-- tabsGroup = TabsGroup() - setGroups(listOf(displayGroup, badgeGroup, /* SY --> */ buttonsGroup, /* SY <-- */ tabsGroup)) + otherGroup = OtherGroup() + setGroups(listOf(displayGroup, badgeGroup, tabsGroup, otherGroup)) } // Refreshes Display Setting selections @@ -444,30 +438,6 @@ class LibrarySettingsSheet( } } - // SY --> - inner class ButtonsGroup : Group { - private val startReadingButton = Item.CheckboxGroup(R.string.action_start_reading_button, this) - - override val header = Item.Header(R.string.buttons_header) - override val items = listOf(startReadingButton) - override val footer = null - - override fun initModels() { - startReadingButton.checked = libraryPreferences.startReadingButton().get() - } - - override fun onItemClicked(item: Item) { - item as Item.CheckboxGroup - item.checked = !item.checked - when (item) { - startReadingButton -> libraryPreferences.startReadingButton().set((item.checked)) - else -> Unit - } - adapter.notifyItemChanged(item) - } - } - // SY <-- - inner class TabsGroup : Group { private val showTabs = Item.CheckboxGroup(R.string.action_display_show_tabs, this) private val showNumberOfItems = Item.CheckboxGroup(R.string.action_display_show_number_of_items, this) @@ -492,6 +462,28 @@ class LibrarySettingsSheet( adapter.notifyItemChanged(item) } } + + inner class OtherGroup : Group { + private val showContinueReadingButton = Item.CheckboxGroup(R.string.action_display_show_continue_reading_button, this) + + override val header = Item.Header(R.string.other_header) + override val items = listOf(showContinueReadingButton) + override val footer = null + + override fun initModels() { + showContinueReadingButton.checked = libraryPreferences.showContinueReadingButton().get() + } + + override fun onItemClicked(item: Item) { + item as Item.CheckboxGroup + item.checked = !item.checked + when (item) { + showContinueReadingButton -> libraryPreferences.showContinueReadingButton().set(item.checked) + else -> {} + } + adapter.notifyItemChanged(item) + } + } } // SY --> diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index 107a59c3e..498fcc20a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -17,6 +17,7 @@ import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay import eu.kanade.domain.chapter.interactor.UpdateChapter import eu.kanade.domain.chapter.model.ChapterUpdate +import eu.kanade.domain.chapter.model.applyFilters import eu.kanade.domain.chapter.model.toDbChapter import eu.kanade.domain.download.service.DownloadPreferences import eu.kanade.domain.library.service.LibraryPreferences @@ -38,7 +39,6 @@ import eu.kanade.domain.manga.interactor.UpdateMergedSettings import eu.kanade.domain.manga.model.MangaUpdate import eu.kanade.domain.manga.model.MergeMangaSettingsUpdate import eu.kanade.domain.manga.model.PagePreview -import eu.kanade.domain.manga.model.TriStateFilter import eu.kanade.domain.manga.model.isLocal import eu.kanade.domain.manga.model.toDbManga import eu.kanade.domain.track.interactor.DeleteTrack @@ -66,6 +66,7 @@ import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.manga.track.TrackItem import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.util.chapter.getChapterSort +import eu.kanade.tachiyomi.util.chapter.getNextUnread import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.toRelativeString @@ -1054,24 +1055,7 @@ class MangaPresenter( */ fun getNextUnreadChapter(): DomainChapter? { val successState = successState ?: return null - // SY --> - if (successState.manga.isEhBasedManga()) { - return successState.processedChapters.map { it.chapter }.let { chapters -> - if (successState.manga.sortDescending()) { - chapters.firstOrNull() - } else { - chapters.lastOrNull() - } - } - } - // SY <-- - return successState.processedChapters.map { it.chapter }.let { chapters -> - if (successState.manga.sortDescending()) { - chapters.findLast { !it.read } - } else { - chapters.find { !it.read } - } - } + return successState.chapters.getNextUnread(successState.manga) } fun getUnreadChapters(): List { @@ -1650,44 +1634,6 @@ sealed class MangaScreenState { val processedChapters: Sequence get() = chapters.applyFilters(manga) - - /** - * Applies the view filters to the list of chapters obtained from the database. - * @return an observable of the list of chapters filtered and sorted. - */ - private fun List.applyFilters(manga: DomainManga): Sequence { - val isLocalManga = manga.isLocal() - val unreadFilter = manga.unreadFilter - val downloadedFilter = manga.downloadedFilter - val bookmarkedFilter = manga.bookmarkedFilter - val filteredScanlators = manga.filteredScanlators.orEmpty() - return asSequence() - .filter { (chapter) -> - when (unreadFilter) { - TriStateFilter.DISABLED -> true - TriStateFilter.ENABLED_IS -> !chapter.read - TriStateFilter.ENABLED_NOT -> chapter.read - } - } - .filter { (chapter) -> - when (bookmarkedFilter) { - TriStateFilter.DISABLED -> true - TriStateFilter.ENABLED_IS -> chapter.bookmark - TriStateFilter.ENABLED_NOT -> !chapter.bookmark - } - } - .filter { - when (downloadedFilter) { - TriStateFilter.DISABLED -> true - TriStateFilter.ENABLED_IS -> it.isDownloaded || isLocalManga - TriStateFilter.ENABLED_NOT -> !it.isDownloaded && !isLocalManga - } - } - .filter { (chapter) -> - filteredScanlators.isEmpty() || MdUtil.getScanlators(chapter.scanlator).any { group -> filteredScanlators.contains(group) } - } - .sortedWith { (chapter1), (chapter2) -> getChapterSort(manga).invoke(chapter1, chapter2) } - } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterGetNextUnread.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterGetNextUnread.kt new file mode 100644 index 000000000..d006d2cf4 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterGetNextUnread.kt @@ -0,0 +1,52 @@ +package eu.kanade.tachiyomi.util.chapter + +import eu.kanade.domain.chapter.model.Chapter +import eu.kanade.domain.chapter.model.applyFilters +import eu.kanade.domain.manga.model.Manga +import eu.kanade.tachiyomi.data.download.DownloadManager +import eu.kanade.tachiyomi.ui.manga.ChapterItem +import exh.source.isEhBasedManga + +/** + * Gets next unread chapter with filters and sorting applied + */ +fun List.getNextUnread(manga: Manga, downloadManager: DownloadManager): Chapter? { + return applyFilters(manga, downloadManager).let { chapters -> + // SY --> + if (manga.isEhBasedManga()) { + return@let if (manga.sortDescending()) { + chapters.firstOrNull()?.takeUnless { it.read } + } else { + chapters.lastOrNull()?.takeUnless { it.read } + } + } + // SY <-- + if (manga.sortDescending()) { + chapters.findLast { !it.read } + } else { + chapters.find { !it.read } + } + } +} + +/** + * Gets next unread chapter with filters and sorting applied + */ +fun List.getNextUnread(manga: Manga): Chapter? { + return applyFilters(manga).let { chapters -> + // SY --> + if (manga.isEhBasedManga()) { + return@let if (manga.sortDescending()) { + chapters.firstOrNull()?.takeUnless { it.chapter.read } + } else { + chapters.lastOrNull()?.takeUnless { it.chapter.read } + } + } + // SY <-- + if (manga.sortDescending()) { + chapters.findLast { !it.chapter.read } + } else { + chapters.find { !it.chapter.read } + } + }?.chapter +} diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 86b770a83..b7f02123b 100755 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -108,6 +108,7 @@ Language Show category tabs Show number of items + Show continue reading button Disable Pin Unpin @@ -579,6 +580,7 @@ Downloaded chapters Badges Tabs + Other