Show missing chapter count between two chapters in chapter list (#10096)

* Show missing chapter count between two chapters in chapter list

Closes #8460

* Fix crash

* Lint

* Review changes

* Lint
This commit is contained in:
AntsyLich
2023-11-02 08:18:19 +06:00
committed by GitHub
parent b3d7c92475
commit 6d538db5f2
4 changed files with 189 additions and 107 deletions

View File

@@ -5,9 +5,11 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.asPaddingValues
@@ -26,7 +28,9 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
@@ -44,6 +48,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.util.fastAll
import androidx.compose.ui.util.fastAny
@@ -61,7 +66,7 @@ import eu.kanade.presentation.util.formatChapterNumber
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.source.getNameForMangaInfo
import eu.kanade.tachiyomi.ui.manga.ChapterItem
import eu.kanade.tachiyomi.ui.manga.ChapterList
import eu.kanade.tachiyomi.ui.manga.MangaScreenModel
import eu.kanade.tachiyomi.util.lang.toRelativeString
import eu.kanade.tachiyomi.util.system.copyToClipboard
@@ -75,8 +80,10 @@ import tachiyomi.presentation.core.components.VerticalFastScroller
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
import tachiyomi.presentation.core.components.material.PullRefresh
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.util.isScrolledToEnd
import tachiyomi.presentation.core.util.isScrollingUp
import tachiyomi.presentation.core.util.secondaryItemAlpha
import java.text.DateFormat
import java.util.Date
@@ -92,7 +99,7 @@ fun MangaScreen(
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
onBackClicked: () -> Unit,
onChapterClicked: (Chapter) -> Unit,
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?,
onAddToLibraryClicked: () -> Unit,
onWebViewClicked: (() -> Unit)?,
onWebViewLongClicked: (() -> Unit)?,
@@ -123,10 +130,10 @@ fun MangaScreen(
onMultiDeleteClicked: (List<Chapter>) -> Unit,
// For chapter swipe
onChapterSwipe: (ChapterItem, LibraryPreferences.ChapterSwipeAction) -> Unit,
onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit,
// Chapter selection
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit,
onAllChapterSelected: (Boolean) -> Unit,
onInvertSelection: () -> Unit,
) {
@@ -225,7 +232,7 @@ private fun MangaScreenSmallImpl(
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
onBackClicked: () -> Unit,
onChapterClicked: (Chapter) -> Unit,
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?,
onAddToLibraryClicked: () -> Unit,
onWebViewClicked: (() -> Unit)?,
onWebViewLongClicked: (() -> Unit)?,
@@ -257,16 +264,17 @@ private fun MangaScreenSmallImpl(
onMultiDeleteClicked: (List<Chapter>) -> Unit,
// For chapter swipe
onChapterSwipe: (ChapterItem, LibraryPreferences.ChapterSwipeAction) -> Unit,
onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit,
// Chapter selection
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit,
onAllChapterSelected: (Boolean) -> Unit,
onInvertSelection: () -> Unit,
) {
val chapterListState = rememberLazyListState()
val chapters = remember(state) { state.processedChapters }
val listItem = remember(state) { state.chapterListItems }
val isAnySelected by remember {
derivedStateOf {
@@ -447,7 +455,8 @@ private fun MangaScreenSmallImpl(
sharedChapterItems(
manga = state.manga,
chapters = chapters,
chapters = listItem,
isAnyChapterSelected = chapters.fastAny { it.selected },
dateRelativeTime = dateRelativeTime,
dateFormat = dateFormat,
chapterSwipeStartAction = chapterSwipeStartAction,
@@ -474,7 +483,7 @@ fun MangaScreenLargeImpl(
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
onBackClicked: () -> Unit,
onChapterClicked: (Chapter) -> Unit,
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?,
onAddToLibraryClicked: () -> Unit,
onWebViewClicked: (() -> Unit)?,
onWebViewLongClicked: (() -> Unit)?,
@@ -506,10 +515,10 @@ fun MangaScreenLargeImpl(
onMultiDeleteClicked: (List<Chapter>) -> Unit,
// For swipe actions
onChapterSwipe: (ChapterItem, LibraryPreferences.ChapterSwipeAction) -> Unit,
onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit,
// Chapter selection
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit,
onAllChapterSelected: (Boolean) -> Unit,
onInvertSelection: () -> Unit,
) {
@@ -517,6 +526,7 @@ fun MangaScreenLargeImpl(
val density = LocalDensity.current
val chapters = remember(state) { state.processedChapters }
val listItem = remember(state) { state.chapterListItems }
val isAnySelected by remember {
derivedStateOf {
@@ -688,7 +698,8 @@ fun MangaScreenLargeImpl(
sharedChapterItems(
manga = state.manga,
chapters = chapters,
chapters = listItem,
isAnyChapterSelected = chapters.fastAny { it.selected },
dateRelativeTime = dateRelativeTime,
dateFormat = dateFormat,
chapterSwipeStartAction = chapterSwipeStartAction,
@@ -708,12 +719,12 @@ fun MangaScreenLargeImpl(
@Composable
private fun SharedMangaBottomActionMenu(
selected: List<ChapterItem>,
selected: List<ChapterList.Item>,
modifier: Modifier = Modifier,
onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit,
onMultiMarkAsReadClicked: (List<Chapter>, markAsRead: Boolean) -> Unit,
onMarkPreviousAsReadClicked: (Chapter) -> Unit,
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?,
onMultiDeleteClicked: (List<Chapter>) -> Unit,
fillFraction: Float,
) {
@@ -750,92 +761,123 @@ private fun SharedMangaBottomActionMenu(
private fun LazyListScope.sharedChapterItems(
manga: Manga,
chapters: List<ChapterItem>,
chapters: List<ChapterList>,
isAnyChapterSelected: Boolean,
dateRelativeTime: Boolean,
dateFormat: DateFormat,
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
onChapterClicked: (Chapter) -> Unit,
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
onChapterSwipe: (ChapterItem, LibraryPreferences.ChapterSwipeAction) -> Unit,
onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?,
onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit,
onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit,
) {
items(
items = chapters,
key = { "chapter-${it.chapter.id}" },
key = { item ->
when (item) {
is ChapterList.MissingCount -> "missing-count-${item.id}"
is ChapterList.Item -> "chapter-${item.id}"
}
},
contentType = { MangaScreenItem.CHAPTER },
) { chapterItem ->
) { item ->
val haptic = LocalHapticFeedback.current
val context = LocalContext.current
MangaChapterListItem(
title = if (manga.displayMode == Manga.CHAPTER_DISPLAY_NUMBER) {
stringResource(
R.string.display_mode_chapter,
formatChapterNumber(chapterItem.chapter.chapterNumber),
)
} else {
chapterItem.chapter.name
},
date = chapterItem.chapter.dateUpload
.takeIf { it > 0L }
?.let {
Date(it).toRelativeString(
context,
dateRelativeTime,
dateFormat,
when (item) {
is ChapterList.MissingCount -> {
Row(
modifier = Modifier.padding(
horizontal = MaterialTheme.padding.medium,
vertical = MaterialTheme.padding.small,
),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.medium),
) {
HorizontalDivider(modifier = Modifier.weight(1f))
Text(
text = pluralStringResource(
id = R.plurals.missing_chapters,
count = item.count,
item.count,
),
modifier = Modifier.secondaryItemAlpha(),
)
},
readProgress = chapterItem.chapter.lastPageRead
.takeIf { !chapterItem.chapter.read && it > 0L }
?.let {
stringResource(
R.string.chapter_progress,
it + 1,
)
},
scanlator = chapterItem.chapter.scanlator.takeIf { !it.isNullOrBlank() },
read = chapterItem.chapter.read,
bookmark = chapterItem.chapter.bookmark,
selected = chapterItem.selected,
downloadIndicatorEnabled = chapters.fastAll { !it.selected },
downloadStateProvider = { chapterItem.downloadState },
downloadProgressProvider = { chapterItem.downloadProgress },
chapterSwipeStartAction = chapterSwipeStartAction,
chapterSwipeEndAction = chapterSwipeEndAction,
onLongClick = {
onChapterSelected(chapterItem, !chapterItem.selected, true, true)
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
},
onClick = {
onChapterItemClick(
chapterItem = chapterItem,
chapters = chapters,
onToggleSelection = { onChapterSelected(chapterItem, !chapterItem.selected, true, false) },
onChapterClicked = onChapterClicked,
HorizontalDivider(modifier = Modifier.weight(1f))
}
}
is ChapterList.Item -> {
MangaChapterListItem(
title = if (manga.displayMode == Manga.CHAPTER_DISPLAY_NUMBER) {
stringResource(
R.string.display_mode_chapter,
formatChapterNumber(item.chapter.chapterNumber),
)
} else {
item.chapter.name
},
date = item.chapter.dateUpload
.takeIf { it > 0L }
?.let {
Date(it).toRelativeString(
context,
dateRelativeTime,
dateFormat,
)
},
readProgress = item.chapter.lastPageRead
.takeIf { !item.chapter.read && it > 0L }
?.let {
stringResource(
R.string.chapter_progress,
it + 1,
)
},
scanlator = item.chapter.scanlator.takeIf { !it.isNullOrBlank() },
read = item.chapter.read,
bookmark = item.chapter.bookmark,
selected = item.selected,
downloadIndicatorEnabled = !isAnyChapterSelected,
downloadStateProvider = { item.downloadState },
downloadProgressProvider = { item.downloadProgress },
chapterSwipeStartAction = chapterSwipeStartAction,
chapterSwipeEndAction = chapterSwipeEndAction,
onLongClick = {
onChapterSelected(item, !item.selected, true, true)
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
},
onClick = {
onChapterItemClick(
chapterItem = item,
isAnyChapterSelected = isAnyChapterSelected,
onToggleSelection = { onChapterSelected(item, !item.selected, true, false) },
onChapterClicked = onChapterClicked,
)
},
onDownloadClick = if (onDownloadChapter != null) {
{ onDownloadChapter(listOf(item), it) }
} else {
null
},
onChapterSwipe = {
onChapterSwipe(item, it)
},
)
},
onDownloadClick = if (onDownloadChapter != null) {
{ onDownloadChapter(listOf(chapterItem), it) }
} else {
null
},
onChapterSwipe = {
onChapterSwipe(chapterItem, it)
},
)
}
}
}
}
private fun onChapterItemClick(
chapterItem: ChapterItem,
chapters: List<ChapterItem>,
chapterItem: ChapterList.Item,
isAnyChapterSelected: Boolean,
onToggleSelection: (Boolean) -> Unit,
onChapterClicked: (Chapter) -> Unit,
) {
when {
chapterItem.selected -> onToggleSelection(false)
chapters.fastAny { it.selected } -> onToggleSelection(true)
isAnyChapterSelected -> onToggleSelection(true)
else -> onChapterClicked(chapterItem.chapter)
}
}