Related titles screen
This commit is contained in:
parent
cdd3a7f6f8
commit
d764ac3b63
5 changed files with 126 additions and 0 deletions
|
|
@ -31,6 +31,7 @@ import androidx.compose.material3.SnackbarHost
|
|||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
|
|
@ -49,6 +50,8 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.util.fastAll
|
||||
import androidx.compose.ui.util.fastAny
|
||||
import androidx.compose.ui.util.fastMap
|
||||
import eu.kanade.presentation.browse.components.GlobalSearchCardRow
|
||||
import eu.kanade.presentation.browse.components.GlobalSearchResultItem
|
||||
import eu.kanade.presentation.components.relativeDateText
|
||||
import eu.kanade.presentation.manga.components.ChapterDownloadAction
|
||||
import eu.kanade.presentation.manga.components.ChapterHeader
|
||||
|
|
@ -167,6 +170,12 @@ fun MangaScreen(
|
|||
onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit,
|
||||
onAllChapterSelected: (Boolean) -> Unit,
|
||||
onInvertSelection: () -> Unit,
|
||||
|
||||
// KMK -->
|
||||
getMangaState: @Composable ((Manga) -> State<Manga>),
|
||||
onRelatedMangaClick: (Manga) -> Unit,
|
||||
onRelatedMangaLongClick: (Manga) -> Unit,
|
||||
// KMK <--
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val onCopyTagToClipboard: (tag: String) -> Unit = {
|
||||
|
|
@ -220,6 +229,11 @@ fun MangaScreen(
|
|||
onChapterSelected = onChapterSelected,
|
||||
onAllChapterSelected = onAllChapterSelected,
|
||||
onInvertSelection = onInvertSelection,
|
||||
// KMK -->
|
||||
getMangaState = getMangaState,
|
||||
onRelatedMangaClick = onRelatedMangaClick,
|
||||
onRelatedMangaLongClick = onRelatedMangaLongClick,
|
||||
// KMK <--
|
||||
)
|
||||
} else {
|
||||
MangaScreenLargeImpl(
|
||||
|
|
@ -266,6 +280,11 @@ fun MangaScreen(
|
|||
onChapterSelected = onChapterSelected,
|
||||
onAllChapterSelected = onAllChapterSelected,
|
||||
onInvertSelection = onInvertSelection,
|
||||
// KMK -->
|
||||
getMangaState = getMangaState,
|
||||
onRelatedMangaClick = onRelatedMangaClick,
|
||||
onRelatedMangaLongClick = onRelatedMangaLongClick,
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -328,6 +347,12 @@ private fun MangaScreenSmallImpl(
|
|||
onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit,
|
||||
onAllChapterSelected: (Boolean) -> Unit,
|
||||
onInvertSelection: () -> Unit,
|
||||
|
||||
// KMK -->
|
||||
getMangaState: @Composable ((Manga) -> State<Manga>),
|
||||
onRelatedMangaClick: (Manga) -> Unit,
|
||||
onRelatedMangaLongClick: (Manga) -> Unit,
|
||||
// KMK <--
|
||||
) {
|
||||
val chapterListState = rememberLazyListState()
|
||||
|
||||
|
|
@ -534,6 +559,29 @@ private fun MangaScreenSmallImpl(
|
|||
)
|
||||
}
|
||||
|
||||
// KMK -->
|
||||
if (state.manga.relatedMangas!!.isNotEmpty()) {
|
||||
item(
|
||||
key = MangaScreenItem.RELATED_TITLES,
|
||||
contentType = MangaScreenItem.RELATED_TITLES,
|
||||
) {
|
||||
GlobalSearchResultItem(
|
||||
title = "Related titles",
|
||||
subtitle = null,
|
||||
onLongClick = null,
|
||||
onClick = { /* Should show a page with grid/list of all the related manga */ },
|
||||
) {
|
||||
RelatedMangas(
|
||||
mangas = state.manga.relatedMangas!!,
|
||||
getMangaState = { getMangaState(it) },
|
||||
onClickManga = onRelatedMangaClick,
|
||||
onLongClickManga = onRelatedMangaLongClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// KMK <--
|
||||
|
||||
// SY -->
|
||||
if (!state.showRecommendationsInOverflow || state.showMergeWithAnother) {
|
||||
item(
|
||||
|
|
@ -654,6 +702,12 @@ fun MangaScreenLargeImpl(
|
|||
onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit,
|
||||
onAllChapterSelected: (Boolean) -> Unit,
|
||||
onInvertSelection: () -> Unit,
|
||||
|
||||
// KMK -->
|
||||
getMangaState: @Composable ((Manga) -> State<Manga>),
|
||||
onRelatedMangaClick: (Manga) -> Unit,
|
||||
onRelatedMangaLongClick: (Manga) -> Unit,
|
||||
// KMK <--
|
||||
) {
|
||||
val layoutDirection = LocalLayoutDirection.current
|
||||
val density = LocalDensity.current
|
||||
|
|
@ -863,6 +917,29 @@ fun MangaScreenLargeImpl(
|
|||
bottom = contentPadding.calculateBottomPadding(),
|
||||
),
|
||||
) {
|
||||
// KMK -->
|
||||
if (state.manga.relatedMangas!!.isNotEmpty()) {
|
||||
item(
|
||||
key = MangaScreenItem.RELATED_TITLES,
|
||||
contentType = MangaScreenItem.RELATED_TITLES,
|
||||
) {
|
||||
GlobalSearchResultItem(
|
||||
title = "Related titles",
|
||||
subtitle = null,
|
||||
onLongClick = null,
|
||||
onClick = { /* Should show a page with grid/list of all the related manga */ },
|
||||
) {
|
||||
RelatedMangas(
|
||||
mangas = state.manga.relatedMangas!!,
|
||||
getMangaState = { getMangaState(it) },
|
||||
onClickManga = onRelatedMangaClick,
|
||||
onLongClickManga = onRelatedMangaLongClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// KMK <--
|
||||
|
||||
item(
|
||||
key = MangaScreenItem.CHAPTER_HEADER,
|
||||
contentType = MangaScreenItem.CHAPTER_HEADER,
|
||||
|
|
@ -900,6 +977,24 @@ fun MangaScreenLargeImpl(
|
|||
}
|
||||
}
|
||||
|
||||
// KMK -->
|
||||
@Composable
|
||||
fun RelatedMangas(
|
||||
mangas: List<Manga>,
|
||||
getMangaState: @Composable ((Manga) -> State<Manga>),
|
||||
onClickManga: (Manga) -> Unit,
|
||||
onLongClickManga: (Manga) -> Unit,
|
||||
) {
|
||||
GlobalSearchCardRow(
|
||||
titles = mangas,
|
||||
getManga = getMangaState,
|
||||
onClick = onClickManga,
|
||||
onLongClick = onLongClickManga,
|
||||
selection = emptyList(),
|
||||
)
|
||||
}
|
||||
// KMK <--
|
||||
|
||||
@Composable
|
||||
private fun SharedMangaBottomActionMenu(
|
||||
selected: List<ChapterList.Item>,
|
||||
|
|
|
|||
|
|
@ -32,4 +32,8 @@ enum class MangaScreenItem {
|
|||
// SY <--
|
||||
CHAPTER_HEADER,
|
||||
CHAPTER,
|
||||
|
||||
// KMK -->
|
||||
RELATED_TITLES,
|
||||
// KMK <--
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,6 +225,11 @@ class MangaScreen(
|
|||
onChapterSelected = screenModel::toggleSelection,
|
||||
onAllChapterSelected = screenModel::toggleAllSelection,
|
||||
onInvertSelection = screenModel::invertSelection,
|
||||
// KMK -->
|
||||
getMangaState = { screenModel.getManga(initialManga = it) },
|
||||
onRelatedMangaClick = { navigator.push(MangaScreen(it.id, true)) },
|
||||
onRelatedMangaLongClick = { },
|
||||
// KMK <--
|
||||
)
|
||||
|
||||
var showScanlatorsDialog by remember { mutableStateOf(false) }
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ package eu.kanade.tachiyomi.ui.manga
|
|||
import android.content.Context
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.SnackbarResult
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.ui.util.fastAny
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
|
|
@ -72,6 +74,7 @@ import kotlinx.coroutines.flow.combine
|
|||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.distinctUntilChangedBy
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.flatMapConcat
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
|
@ -135,6 +138,7 @@ import uy.kohesive.injekt.Injekt
|
|||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.math.floor
|
||||
import androidx.compose.runtime.State as RuntimeState
|
||||
|
||||
class MangaScreenModel(
|
||||
val context: Context,
|
||||
|
|
@ -553,6 +557,19 @@ class MangaScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
// KMK -->
|
||||
@Composable
|
||||
fun getManga(initialManga: Manga): RuntimeState<Manga> {
|
||||
return produceState(initialValue = initialManga) {
|
||||
getManga.subscribe(initialManga.url, initialManga.source)
|
||||
.filterNotNull()
|
||||
.collectLatest { manga ->
|
||||
value = manga
|
||||
}
|
||||
}
|
||||
}
|
||||
// KMK <--
|
||||
|
||||
suspend fun smartSearchMerge(manga: Manga, originalMangaId: Long): Manga {
|
||||
val originalManga = getManga.await(originalMangaId)
|
||||
?: throw IllegalArgumentException(context.stringResource(SYMR.strings.merge_unknown_entry, originalMangaId))
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@ data class Manga(
|
|||
get() = customMangaInfo?.status ?: ogStatus
|
||||
// SY <--
|
||||
|
||||
// KMK -->
|
||||
val relatedMangas: List<Manga>?
|
||||
get() = listOf(this, this, this, this, this, this, this, this, this, this, this, this, this)
|
||||
// KMK <--
|
||||
|
||||
val expectedNextUpdate: Instant?
|
||||
get() = nextUpdate
|
||||
.takeIf { status != SManga.COMPLETED.toLong() }
|
||||
|
|
|
|||
Loading…
Reference in a new issue