Add "Play" button on manga in library (#8218)

* resume manga button in libarary

* work on resume button

* Backup

* work on opening the last read chapter

* backup

* renaming

* fab instead of image

* done with logic

* cleanup

* cleanup

* import cleanup

* cleanup...

* refactoring

* fixing logic

* fixing scopes

* Reworking design

* adding ability to turn on/off the feature

* cleanup

* refactoring, fixing logic, adding filter logic (partial)

* backup

* backup

* logic done

* backup before merge fix

* merge conflict....

* merge conflict...

* reworking ui logic

* removing unnecessary file

* refactoring

* refactoring

* review changes + minor parameter position movement

* commiting suggestion

Co-authored-by: arkon <arkon@users.noreply.github.com>

* fixing minor mistake

* moving ChapterFilter.kt

Co-authored-by: arkon <arkon@users.noreply.github.com>
(cherry picked from commit ba00d9e5d2c00b9cf415932bb2821bf9914fe248)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/components/CommonMangaItem.kt
#	app/src/main/java/eu/kanade/presentation/library/LibraryScreen.kt
#	app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt
#	app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt
#	app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt
#	app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt
This commit is contained in:
d-najd 2022-11-08 04:32:23 +01:00 committed by Jobobby04
parent 206aab6755
commit 1903453ce7
15 changed files with 305 additions and 219 deletions

View File

@ -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<Chapter>.applyFilters(manga: Manga, downloadManager: DownloadManager): List<Chapter> {
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<ChapterItem>.applyFilters(manga: Manga): Sequence<ChapterItem> {
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) }
}

View File

@ -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 <--

View File

@ -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),
)
}
}

View File

@ -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 <--
)

View File

@ -18,19 +18,15 @@ fun LibraryComfortableGrid(
showUnreadBadges: Boolean,
showLocalBadges: Boolean,
showLanguageBadges: Boolean,
// SY -->
showStartReadingButton: Boolean,
// SY <--
showContinueReadingButton: Boolean,
columns: Int,
contentPadding: PaddingValues,
selection: List<LibraryManga>,
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) },
)
}
}

View File

@ -19,19 +19,15 @@ fun LibraryCompactGrid(
showUnreadBadges: Boolean,
showLocalBadges: Boolean,
showLanguageBadges: Boolean,
// SY -->
showStartReadingButton: Boolean,
// SY <--
showContinueReadingButton: Boolean,
columns: Int,
contentPadding: PaddingValues,
selection: List<LibraryManga>,
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) },
)
}
}

View File

@ -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 <--
)
}

View File

@ -27,10 +27,12 @@ fun LibraryList(
showUnreadBadges: Boolean,
showLocalBadges: Boolean,
showLanguageBadges: Boolean,
showContinueReadingButton: Boolean,
contentPadding: PaddingValues,
selection: List<LibraryManga>,
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) },
)
}
}

View File

@ -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 <--
)
}
}

View File

@ -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<UnsortedPreferences>().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
}

View File

@ -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<Long, List<LibraryItem>>
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.
*

View File

@ -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 -->

View File

@ -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<DomainChapter> {
@ -1650,44 +1634,6 @@ sealed class MangaScreenState {
val processedChapters: Sequence<ChapterItem>
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<ChapterItem>.applyFilters(manga: DomainManga): Sequence<ChapterItem> {
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) }
}
}
}

View File

@ -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<Chapter>.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<ChapterItem>.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
}

View File

@ -108,6 +108,7 @@
<string name="action_display_language_badge">Language</string>
<string name="action_display_show_tabs">Show category tabs</string>
<string name="action_display_show_number_of_items">Show number of items</string>
<string name="action_display_show_continue_reading_button">Show continue reading button</string>
<string name="action_disable">Disable</string>
<string name="action_pin">Pin</string>
<string name="action_unpin">Unpin</string>
@ -579,6 +580,7 @@
<string name="downloaded_chapters">Downloaded chapters</string>
<string name="badges_header">Badges</string>
<string name="tabs_header">Tabs</string>
<string name="other_header">Other</string>
<!-- Catalogue fragment -->
<!-- missing prompt after Compose rewrite #7901 -->