|
@@ -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,
|
|
|
- )
|
|
|
- },
|
|
|
- readProgress = chapterItem.chapter.lastPageRead
|
|
|
- .takeIf { !chapterItem.chapter.read && it > 0L }
|
|
|
- ?.let {
|
|
|
- stringResource(
|
|
|
- R.string.chapter_progress,
|
|
|
- it + 1,
|
|
|
+ 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(),
|
|
|
)
|
|
|
- },
|
|
|
- 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)
|
|
|
}
|
|
|
}
|