Fast browsing (#612)
* BrowseTab: serialized data object must have readResolve * simplify usage of bulk-selection select-all/reverse * hide bulk-selection select-all/reverse * fast browsing by avoid insert every entries into DB
This commit is contained in:
parent
1f3d2cbd3c
commit
5fc9e202e8
25 changed files with 338 additions and 201 deletions
|
|
@ -12,7 +12,6 @@ import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.SnackbarResult
|
import androidx.compose.material3.SnackbarResult
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.paging.LoadState
|
import androidx.paging.LoadState
|
||||||
|
|
@ -24,7 +23,6 @@ import eu.kanade.presentation.browse.components.BrowseSourceList
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.util.formattedMessage
|
import eu.kanade.presentation.util.formattedMessage
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
|
|
||||||
import exh.metadata.metadata.RaisedSearchMetadata
|
import exh.metadata.metadata.RaisedSearchMetadata
|
||||||
import exh.source.isEhBasedSource
|
import exh.source.isEhBasedSource
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
@ -62,7 +60,6 @@ fun BrowseSourceContent(
|
||||||
onMangaLongClick: (Manga) -> Unit,
|
onMangaLongClick: (Manga) -> Unit,
|
||||||
// KMK -->
|
// KMK -->
|
||||||
selection: List<Manga>,
|
selection: List<Manga>,
|
||||||
browseSourceState: BrowseSourceScreenModel.State,
|
|
||||||
// KMK <--
|
// KMK <--
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
@ -138,22 +135,9 @@ fun BrowseSourceContent(
|
||||||
LoadingScreen(
|
LoadingScreen(
|
||||||
modifier = Modifier.padding(contentPadding),
|
modifier = Modifier.padding(contentPadding),
|
||||||
)
|
)
|
||||||
// KMK -->
|
|
||||||
browseSourceState.mangaDisplayingList.clear()
|
|
||||||
// KMK <--
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// KMK -->
|
|
||||||
for (idx in browseSourceState.mangaDisplayingList.size..<mangaList.itemCount) {
|
|
||||||
mangaList[idx]?.collectAsState()?.value?.first?.let { manga ->
|
|
||||||
if (!browseSourceState.mangaDisplayingList.map { it.id }.contains(manga.id)) {
|
|
||||||
browseSourceState.mangaDisplayingList.add(manga)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// KMK <--
|
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
if (source?.isEhBasedSource() == true && ehentaiBrowseDisplayMode) {
|
if (source?.isEhBasedSource() == true && ehentaiBrowseDisplayMode) {
|
||||||
BrowseSourceEHentaiList(
|
BrowseSourceEHentaiList(
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ fun RelatedMangasComfortableGrid(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
items(
|
items(
|
||||||
key = { "related-comfort-${relatedManga.mangaList[it].id}" },
|
key = { "related-comfort-${relatedManga.mangaList[it].url.hashCode()}" },
|
||||||
count = relatedManga.mangaList.size,
|
count = relatedManga.mangaList.size,
|
||||||
) { index ->
|
) { index ->
|
||||||
val manga by getManga(relatedManga.mangaList[index])
|
val manga by getManga(relatedManga.mangaList[index])
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ fun RelatedMangasCompactGrid(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
items(
|
items(
|
||||||
key = { "related-compact-${relatedManga.mangaList[it].id}" },
|
key = { "related-compact-${relatedManga.mangaList[it].url.hashCode()}" },
|
||||||
count = relatedManga.mangaList.size,
|
count = relatedManga.mangaList.size,
|
||||||
) { index ->
|
) { index ->
|
||||||
val manga by getManga(relatedManga.mangaList[index])
|
val manga by getManga(relatedManga.mangaList[index])
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ fun RelatedMangasList(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
items(
|
items(
|
||||||
key = { "related-list-${relatedManga.mangaList[it].id}" },
|
key = { "related-list-${relatedManga.mangaList[it].url.hashCode()}" },
|
||||||
count = relatedManga.mangaList.size,
|
count = relatedManga.mangaList.size,
|
||||||
) { index ->
|
) { index ->
|
||||||
val manga by getManga(relatedManga.mangaList[index])
|
val manga by getManga(relatedManga.mangaList[index])
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@ import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Favorite
|
import androidx.compose.material.icons.filled.Favorite
|
||||||
import androidx.compose.material.icons.filled.SelectAll
|
|
||||||
import androidx.compose.material.icons.outlined.FlipToBack
|
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -33,6 +31,7 @@ fun BulkSelectionToolbar(
|
||||||
actions = persistentListOf<AppBar.AppBarAction>()
|
actions = persistentListOf<AppBar.AppBarAction>()
|
||||||
.builder()
|
.builder()
|
||||||
.apply {
|
.apply {
|
||||||
|
/*
|
||||||
if (onSelectAll != null) {
|
if (onSelectAll != null) {
|
||||||
add(
|
add(
|
||||||
AppBar.Action(
|
AppBar.Action(
|
||||||
|
|
@ -51,6 +50,7 @@ fun BulkSelectionToolbar(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
add(
|
add(
|
||||||
AppBar.ActionCompose(
|
AppBar.ActionCompose(
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ fun RelatedMangaCardRow(
|
||||||
contentPadding = PaddingValues(MaterialTheme.padding.small),
|
contentPadding = PaddingValues(MaterialTheme.padding.small),
|
||||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.extraSmall),
|
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.extraSmall),
|
||||||
) {
|
) {
|
||||||
items(mangas, key = { "related-row-${it.id}" }) {
|
items(mangas, key = { "related-row-${it.url.hashCode()}" }) {
|
||||||
val manga by getManga(it)
|
val manga by getManga(it)
|
||||||
MangaItem(
|
MangaItem(
|
||||||
title = manga.title,
|
title = manga.title,
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
data object BrowseTab : Tab {
|
data object BrowseTab : Tab {
|
||||||
|
private fun readResolve(): Any = BrowseTab
|
||||||
|
|
||||||
override val options: TabOptions
|
override val options: TabOptions
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.hapticfeedback.HapticFeedback
|
import androidx.compose.ui.hapticfeedback.HapticFeedback
|
||||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
import androidx.compose.ui.util.fastAny
|
import androidx.compose.ui.util.fastAny
|
||||||
|
import androidx.compose.ui.util.fastDistinctBy
|
||||||
import androidx.compose.ui.util.fastForEach
|
import androidx.compose.ui.util.fastForEach
|
||||||
import androidx.compose.ui.util.fastForEachIndexed
|
import androidx.compose.ui.util.fastForEachIndexed
|
||||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
|
|
@ -113,7 +114,9 @@ class BulkFavoriteScreenModel(
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
val newSelection = mangas.filterNot { manga ->
|
val newSelection = mangas.filterNot { manga ->
|
||||||
state.selection.contains(manga)
|
state.selection.contains(manga)
|
||||||
}.toPersistentList()
|
}
|
||||||
|
.fastDistinctBy { it.id }
|
||||||
|
.toPersistentList()
|
||||||
state.copy(
|
state.copy(
|
||||||
selection = newSelection,
|
selection = newSelection,
|
||||||
selectionMode = newSelection.isNotEmpty(),
|
selectionMode = newSelection.isNotEmpty(),
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
|
|
@ -58,7 +59,7 @@ open class FeedScreenModel(
|
||||||
val sourceManager: SourceManager = Injekt.get(),
|
val sourceManager: SourceManager = Injekt.get(),
|
||||||
val sourcePreferences: SourcePreferences = Injekt.get(),
|
val sourcePreferences: SourcePreferences = Injekt.get(),
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga = Injekt.get(),
|
||||||
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||||
getFeedSavedSearchGlobal: GetFeedSavedSearchGlobal = Injekt.get(),
|
getFeedSavedSearchGlobal: GetFeedSavedSearchGlobal = Injekt.get(),
|
||||||
private val getSavedSearchGlobalFeed: GetSavedSearchGlobalFeed = Injekt.get(),
|
private val getSavedSearchGlobalFeed: GetSavedSearchGlobalFeed = Injekt.get(),
|
||||||
private val countFeedSavedSearchGlobal: CountFeedSavedSearchGlobal = Injekt.get(),
|
private val countFeedSavedSearchGlobal: CountFeedSavedSearchGlobal = Injekt.get(),
|
||||||
|
|
@ -318,9 +319,9 @@ open class FeedScreenModel(
|
||||||
val result = withIOContext {
|
val result = withIOContext {
|
||||||
itemUI.copy(
|
itemUI.copy(
|
||||||
results = page.map {
|
results = page.map {
|
||||||
networkToLocalManga.await(it.toDomainManga(itemUI.source!!.id))
|
|
||||||
}
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
it.toDomainManga(itemUI.source!!.id)
|
||||||
|
}
|
||||||
.filter { !hideInLibraryFeedItems.get() || !it.favorite },
|
.filter { !hideInLibraryFeedItems.get() || !it.favorite },
|
||||||
// KMK <--
|
// KMK <--
|
||||||
)
|
)
|
||||||
|
|
@ -355,8 +356,10 @@ open class FeedScreenModel(
|
||||||
return produceState(initialValue = initialManga) {
|
return produceState(initialValue = initialManga) {
|
||||||
getManga.subscribe(initialManga.url, initialManga.source)
|
getManga.subscribe(initialManga.url, initialManga.source)
|
||||||
.collectLatest { manga ->
|
.collectLatest { manga ->
|
||||||
if (manga == null) return@collectLatest
|
|
||||||
value = manga
|
value = manga
|
||||||
|
// KMK -->
|
||||||
|
?: initialManga
|
||||||
|
// KMK <--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import cafe.adriel.voyager.core.stack.StackEvent
|
import cafe.adriel.voyager.core.stack.StackEvent
|
||||||
|
|
@ -40,6 +41,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.domain.source.interactor.GetRemoteManga
|
import tachiyomi.domain.source.interactor.GetRemoteManga
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.i18n.kmk.KMR
|
import tachiyomi.i18n.kmk.KMR
|
||||||
|
|
@ -57,6 +59,7 @@ fun feedTab(
|
||||||
val state by screenModel.state.collectAsState()
|
val state by screenModel.state.collectAsState()
|
||||||
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||||
val showingFeedOrderScreen = rememberSaveable { mutableStateOf(false) }
|
val showingFeedOrderScreen = rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
|
|
@ -175,21 +178,27 @@ fun feedTab(
|
||||||
// KMK -->
|
// KMK -->
|
||||||
onLongClickFeed = screenModel::openActionsDialog,
|
onLongClickFeed = screenModel::openActionsDialog,
|
||||||
// KMK <--
|
// KMK <--
|
||||||
onClickManga = { manga ->
|
onClickManga = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||||
navigator.push(MangaScreen(manga.id, true))
|
} else {
|
||||||
|
// KMK <--
|
||||||
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// KMK -->
|
// KMK -->
|
||||||
onLongClickManga = { manga ->
|
onLongClickManga = {
|
||||||
if (!bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (!bulkFavoriteState.selectionMode) {
|
||||||
navigator.push(MangaScreen(manga.id, true))
|
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||||
|
} else {
|
||||||
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selection = bulkFavoriteState.selection,
|
selection = bulkFavoriteState.selection,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
|
@ -14,6 +15,7 @@ import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel
|
||||||
import eu.kanade.tachiyomi.ui.browse.ChangeMangasCategoryDialog
|
import eu.kanade.tachiyomi.ui.browse.ChangeMangasCategoryDialog
|
||||||
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListScreen
|
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListScreen
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||||
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
|
|
||||||
class MigrateSearchScreen(private val mangaId: Long, private val validSources: List<Long>) : Screen() {
|
class MigrateSearchScreen(private val mangaId: Long, private val validSources: List<Long>) : Screen() {
|
||||||
|
|
||||||
|
|
@ -28,6 +30,7 @@ class MigrateSearchScreen(private val mangaId: Long, private val validSources: L
|
||||||
val dialogState by dialogScreenModel.state.collectAsState()
|
val dialogState by dialogScreenModel.state.collectAsState()
|
||||||
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
||||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||||
|
|
||||||
|
|
@ -52,21 +55,31 @@ class MigrateSearchScreen(private val mangaId: Long, private val validSources: L
|
||||||
},
|
},
|
||||||
onClickItem = {
|
onClickItem = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.toggleSelection(it)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else
|
if (bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||||
{
|
} else
|
||||||
// SY -->
|
// KMK <--
|
||||||
navigator.items
|
{
|
||||||
.filterIsInstance<MigrationListScreen>()
|
// SY -->
|
||||||
.last()
|
navigator.items
|
||||||
.newSelectedItem = mangaId to it.id
|
.filterIsInstance<MigrationListScreen>()
|
||||||
navigator.popUntil { it is MigrationListScreen }
|
.last()
|
||||||
// SY <--
|
.newSelectedItem = mangaId to manga.id
|
||||||
}
|
navigator.popUntil { it is MigrationListScreen }
|
||||||
|
// SY <--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLongClickItem = {
|
||||||
|
// KMK -->
|
||||||
|
scope.launchIO {
|
||||||
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
|
// KMK <--
|
||||||
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onLongClickItem = { navigator.push(MangaScreen(it.id, true)) },
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
bulkFavoriteScreenModel = bulkFavoriteScreenModel,
|
bulkFavoriteScreenModel = bulkFavoriteScreenModel,
|
||||||
hasPinnedSources = screenModel.hasPinnedSources(),
|
hasPinnedSources = screenModel.hasPinnedSources(),
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
|
|
@ -34,6 +35,7 @@ import eu.kanade.tachiyomi.util.system.toast
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import mihon.presentation.core.util.collectAsLazyPagingItems
|
import mihon.presentation.core.util.collectAsLazyPagingItems
|
||||||
import tachiyomi.core.common.Constants
|
import tachiyomi.core.common.Constants
|
||||||
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.i18n.sy.SYMR
|
import tachiyomi.i18n.sy.SYMR
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
|
|
@ -67,6 +69,7 @@ data class SourceSearchScreen(
|
||||||
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
||||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||||
|
|
@ -74,6 +77,8 @@ data class SourceSearchScreen(
|
||||||
BackHandler(enabled = bulkFavoriteState.selectionMode) {
|
BackHandler(enabled = bulkFavoriteState.selectionMode) {
|
||||||
bulkFavoriteScreenModel.toggleSelectionMode()
|
bulkFavoriteScreenModel.toggleSelectionMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val mangaList = screenModel.mangaPagerFlowFlow.collectAsLazyPagingItems()
|
||||||
// KMK <--
|
// KMK <--
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
|
@ -86,12 +91,17 @@ data class SourceSearchScreen(
|
||||||
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
|
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
|
||||||
onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite,
|
onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite,
|
||||||
onSelectAll = {
|
onSelectAll = {
|
||||||
state.mangaDisplayingList.forEach { manga ->
|
mangaList.itemSnapshotList.items
|
||||||
bulkFavoriteScreenModel.select(manga)
|
.map { it.value.first }
|
||||||
}
|
.forEach { manga ->
|
||||||
|
bulkFavoriteScreenModel.select(manga)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onReverseSelection = {
|
onReverseSelection = {
|
||||||
bulkFavoriteScreenModel.reverseSelection(state.mangaDisplayingList.toList())
|
bulkFavoriteScreenModel.reverseSelection(
|
||||||
|
mangaList.itemSnapshotList.items
|
||||||
|
.map { it.value.first },
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -138,7 +148,7 @@ data class SourceSearchScreen(
|
||||||
}
|
}
|
||||||
BrowseSourceContent(
|
BrowseSourceContent(
|
||||||
source = screenModel.source,
|
source = screenModel.source,
|
||||||
mangaList = screenModel.mangaPagerFlowFlow.collectAsLazyPagingItems(),
|
mangaList = mangaList,
|
||||||
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
||||||
// SY -->
|
// SY -->
|
||||||
ehentaiBrowseDisplayMode = screenModel.ehentaiBrowseDisplayMode,
|
ehentaiBrowseDisplayMode = screenModel.ehentaiBrowseDisplayMode,
|
||||||
|
|
@ -158,19 +168,28 @@ data class SourceSearchScreen(
|
||||||
},
|
},
|
||||||
onHelpClick = { uriHandler.openUri(Constants.URL_HELP) },
|
onHelpClick = { uriHandler.openUri(Constants.URL_HELP) },
|
||||||
onLocalSourceHelpClick = { uriHandler.openUri(LocalSource.HELP_URL) },
|
onLocalSourceHelpClick = { uriHandler.openUri(LocalSource.HELP_URL) },
|
||||||
onMangaClick = { manga ->
|
onMangaClick = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||||
openMigrateDialog(manga)
|
} else {
|
||||||
|
// KMK <--
|
||||||
|
openMigrateDialog(manga)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMangaLongClick = {
|
||||||
|
// KMK -->
|
||||||
|
scope.launchIO {
|
||||||
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
|
// KMK <--
|
||||||
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMangaLongClick = { navigator.push(MangaScreen(it.id, true)) },
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
selection = bulkFavoriteState.selection,
|
selection = bulkFavoriteState.selection,
|
||||||
browseSourceState = state,
|
|
||||||
// KMK <--
|
// KMK <--
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,9 @@ data class BrowseSourceScreen(
|
||||||
assistUrl = (screenModel.source as? HttpSource)?.baseUrl
|
assistUrl = (screenModel.source as? HttpSource)?.baseUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KMK -->
|
||||||
|
val mangaList = screenModel.mangaPagerFlowFlow.collectAsLazyPagingItems()
|
||||||
|
// KMK <--
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) {
|
Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) {
|
||||||
|
|
@ -182,12 +185,17 @@ data class BrowseSourceScreen(
|
||||||
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
|
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
|
||||||
onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite,
|
onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite,
|
||||||
onSelectAll = {
|
onSelectAll = {
|
||||||
state.mangaDisplayingList.forEach { manga ->
|
mangaList.itemSnapshotList.items
|
||||||
bulkFavoriteScreenModel.select(manga)
|
.map { it.value.first }
|
||||||
}
|
.forEach { manga ->
|
||||||
|
bulkFavoriteScreenModel.select(manga)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onReverseSelection = {
|
onReverseSelection = {
|
||||||
bulkFavoriteScreenModel.reverseSelection(state.mangaDisplayingList.toList())
|
bulkFavoriteScreenModel.reverseSelection(
|
||||||
|
mangaList.itemSnapshotList.items
|
||||||
|
.map { it.value.first },
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -314,7 +322,7 @@ data class BrowseSourceScreen(
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
BrowseSourceContent(
|
BrowseSourceContent(
|
||||||
source = screenModel.source,
|
source = screenModel.source,
|
||||||
mangaList = screenModel.mangaPagerFlowFlow.collectAsLazyPagingItems(),
|
mangaList = mangaList,
|
||||||
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
||||||
// SY -->
|
// SY -->
|
||||||
ehentaiBrowseDisplayMode = screenModel.ehentaiBrowseDisplayMode,
|
ehentaiBrowseDisplayMode = screenModel.ehentaiBrowseDisplayMode,
|
||||||
|
|
@ -327,30 +335,34 @@ data class BrowseSourceScreen(
|
||||||
onLocalSourceHelpClick = onHelpClick,
|
onLocalSourceHelpClick = onHelpClick,
|
||||||
onMangaClick = {
|
onMangaClick = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.toggleSelection(it)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||||
navigator.push(
|
} else {
|
||||||
MangaScreen(
|
// KMK <--
|
||||||
it.id,
|
navigator.push(
|
||||||
// KMK -->
|
MangaScreen(
|
||||||
// Finding the entry to be merged to, so we don't want to expand description
|
manga.id,
|
||||||
// so that user can see the `Merge to another` button
|
// KMK -->
|
||||||
smartSearchConfig != null,
|
// Finding the entry to be merged to, so we don't want to expand description
|
||||||
// KMK <--
|
// so that user can see the `Merge to another` button
|
||||||
smartSearchConfig,
|
smartSearchConfig != null,
|
||||||
),
|
// KMK <--
|
||||||
)
|
smartSearchConfig,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMangaLongClick = { manga ->
|
onMangaLongClick = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
navigator.push(MangaScreen(manga.id, true))
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
scope.launchIO {
|
} else {
|
||||||
|
// KMK <--
|
||||||
val duplicateManga = screenModel.getDuplicateLibraryManga(manga)
|
val duplicateManga = screenModel.getDuplicateLibraryManga(manga)
|
||||||
when {
|
when {
|
||||||
manga.favorite -> screenModel.setDialog(
|
manga.favorite -> screenModel.setDialog(
|
||||||
|
|
@ -370,7 +382,6 @@ data class BrowseSourceScreen(
|
||||||
},
|
},
|
||||||
// KMK -->
|
// KMK -->
|
||||||
selection = bulkFavoriteState.selection,
|
selection = bulkFavoriteState.selection,
|
||||||
browseSourceState = state,
|
|
||||||
// KMK <--
|
// KMK <--
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@ import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.emptyFlow
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
|
@ -103,7 +102,7 @@ open class BrowseSourceScreenModel(
|
||||||
private val setMangaCategories: SetMangaCategories = Injekt.get(),
|
private val setMangaCategories: SetMangaCategories = Injekt.get(),
|
||||||
private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(),
|
private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(),
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga = Injekt.get(),
|
||||||
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||||
private val updateManga: UpdateManga = Injekt.get(),
|
private val updateManga: UpdateManga = Injekt.get(),
|
||||||
private val addTracks: AddTracks = Injekt.get(),
|
private val addTracks: AddTracks = Injekt.get(),
|
||||||
|
|
||||||
|
|
@ -212,9 +211,13 @@ open class BrowseSourceScreenModel(
|
||||||
// SY <--
|
// SY <--
|
||||||
}.flow.map { pagingData ->
|
}.flow.map { pagingData ->
|
||||||
pagingData.map { (it, metadata) ->
|
pagingData.map { (it, metadata) ->
|
||||||
networkToLocalManga.await(it.toDomainManga(sourceId))
|
// KMK -->
|
||||||
.let { localManga -> getManga.subscribe(localManga.url, localManga.source) }
|
it.toDomainManga(sourceId)
|
||||||
.filterNotNull()
|
.let { manga ->
|
||||||
|
getManga.subscribe(manga.url, manga.source)
|
||||||
|
.map { it ?: manga }
|
||||||
|
}
|
||||||
|
// KMK <--
|
||||||
// SY -->
|
// SY -->
|
||||||
.combineMetadata(metadata)
|
.combineMetadata(metadata)
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
@ -520,9 +523,6 @@ open class BrowseSourceScreenModel(
|
||||||
val savedSearches: ImmutableList<EXHSavedSearch> = persistentListOf(),
|
val savedSearches: ImmutableList<EXHSavedSearch> = persistentListOf(),
|
||||||
val filterable: Boolean = true,
|
val filterable: Boolean = true,
|
||||||
// SY <--
|
// SY <--
|
||||||
// KMK -->
|
|
||||||
val mangaDisplayingList: MutableSet<Manga> = mutableSetOf(),
|
|
||||||
// KMK <--
|
|
||||||
) {
|
) {
|
||||||
val isUserQuery get() = listing is Listing.Search && !listing.query.isNullOrEmpty()
|
val isUserQuery get() = listing is Listing.Search && !listing.query.isNullOrEmpty()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
|
|
@ -43,6 +44,7 @@ import eu.kanade.tachiyomi.util.system.toast
|
||||||
import exh.md.follows.MangaDexFollowsScreen
|
import exh.md.follows.MangaDexFollowsScreen
|
||||||
import exh.source.isEhBasedSource
|
import exh.source.isEhBasedSource
|
||||||
import exh.util.nullIfBlank
|
import exh.util.nullIfBlank
|
||||||
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.interactor.GetRemoteManga
|
import tachiyomi.domain.source.interactor.GetRemoteManga
|
||||||
import tachiyomi.domain.source.model.SavedSearch
|
import tachiyomi.domain.source.model.SavedSearch
|
||||||
|
|
@ -67,6 +69,7 @@ class SourceFeedScreen(val sourceId: Long) : Screen() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
screenModel.source.let {
|
screenModel.source.let {
|
||||||
if (it is StubSource) {
|
if (it is StubSource) {
|
||||||
MissingSourceScreen(
|
MissingSourceScreen(
|
||||||
|
|
@ -126,11 +129,14 @@ class SourceFeedScreen(val sourceId: Long) : Screen() {
|
||||||
// KMK <--
|
// KMK <--
|
||||||
onClickManga = {
|
onClickManga = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.toggleSelection(it)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||||
onMangaClick(navigator, it)
|
} else {
|
||||||
|
// KMK <--
|
||||||
|
onMangaClick(navigator, manga)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClickSearch = { onSearchClick(navigator, screenModel.source, it) },
|
onClickSearch = { onSearchClick(navigator, screenModel.source, it) },
|
||||||
|
|
@ -173,11 +179,14 @@ class SourceFeedScreen(val sourceId: Long) : Screen() {
|
||||||
.filterIsInstance<SourceFeedUI.SourceSavedSearch>()
|
.filterIsInstance<SourceFeedUI.SourceSavedSearch>()
|
||||||
.isNotEmpty()
|
.isNotEmpty()
|
||||||
},
|
},
|
||||||
onLongClickManga = { manga ->
|
onLongClickManga = {
|
||||||
if (!bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (!bulkFavoriteState.selectionMode) {
|
||||||
navigator.push(MangaScreen(manga.id, true))
|
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||||
|
} else {
|
||||||
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
bulkFavoriteScreenModel = bulkFavoriteScreenModel,
|
bulkFavoriteScreenModel = bulkFavoriteScreenModel,
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ open class SourceFeedScreenModel(
|
||||||
uiPreferences: UiPreferences = Injekt.get(),
|
uiPreferences: UiPreferences = Injekt.get(),
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga = Injekt.get(),
|
||||||
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||||
private val getFeedSavedSearchBySourceId: GetFeedSavedSearchBySourceId = Injekt.get(),
|
private val getFeedSavedSearchBySourceId: GetFeedSavedSearchBySourceId = Injekt.get(),
|
||||||
private val getSavedSearchBySourceIdFeed: GetSavedSearchBySourceIdFeed = Injekt.get(),
|
private val getSavedSearchBySourceIdFeed: GetSavedSearchBySourceIdFeed = Injekt.get(),
|
||||||
private val countFeedSavedSearchBySourceId: CountFeedSavedSearchBySourceId = Injekt.get(),
|
private val countFeedSavedSearchBySourceId: CountFeedSavedSearchBySourceId = Injekt.get(),
|
||||||
|
|
@ -236,7 +236,9 @@ open class SourceFeedScreenModel(
|
||||||
|
|
||||||
val titles = withIOContext {
|
val titles = withIOContext {
|
||||||
page.map {
|
page.map {
|
||||||
networkToLocalManga.await(it.toDomainManga(source.id))
|
// KMK -->
|
||||||
|
it.toDomainManga(source.id)
|
||||||
|
// KMK <--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,8 +273,10 @@ open class SourceFeedScreenModel(
|
||||||
return produceState(initialValue = initialManga) {
|
return produceState(initialValue = initialManga) {
|
||||||
getManga.subscribe(initialManga.url, initialManga.source)
|
getManga.subscribe(initialManga.url, initialManga.source)
|
||||||
.collectLatest { manga ->
|
.collectLatest { manga ->
|
||||||
if (manga == null) return@collectLatest
|
|
||||||
value = manga
|
value = manga
|
||||||
|
// KMK -->
|
||||||
|
?: initialManga
|
||||||
|
// KMK <--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||||
|
|
@ -23,6 +24,7 @@ import eu.kanade.tachiyomi.ui.browse.ChangeMangasCategoryDialog
|
||||||
import eu.kanade.tachiyomi.ui.browse.RemoveMangaDialog
|
import eu.kanade.tachiyomi.ui.browse.RemoveMangaDialog
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||||
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||||
|
|
||||||
class GlobalSearchScreen(
|
class GlobalSearchScreen(
|
||||||
|
|
@ -51,6 +53,7 @@ class GlobalSearchScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
||||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||||
|
|
||||||
|
|
@ -93,20 +96,26 @@ class GlobalSearchScreen(
|
||||||
},
|
},
|
||||||
onClickItem = {
|
onClickItem = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.toggleSelection(it)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||||
navigator.push(MangaScreen(it.id, true))
|
} else {
|
||||||
|
// KMK <--
|
||||||
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLongClickItem = { manga ->
|
onLongClickItem = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (!bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (!bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||||
navigator.push(MangaScreen(manga.id, true))
|
} else {
|
||||||
|
// KMK <--
|
||||||
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import kotlinx.coroutines.asCoroutineDispatcher
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -39,7 +39,7 @@ abstract class SearchScreenModel(
|
||||||
sourcePreferences: SourcePreferences = Injekt.get(),
|
sourcePreferences: SourcePreferences = Injekt.get(),
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
private val extensionManager: ExtensionManager = Injekt.get(),
|
private val extensionManager: ExtensionManager = Injekt.get(),
|
||||||
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga = Injekt.get(),
|
||||||
private val preferences: SourcePreferences = Injekt.get(),
|
private val preferences: SourcePreferences = Injekt.get(),
|
||||||
) : StateScreenModel<SearchScreenModel.State>(initialState) {
|
) : StateScreenModel<SearchScreenModel.State>(initialState) {
|
||||||
|
|
@ -83,9 +83,11 @@ abstract class SearchScreenModel(
|
||||||
fun getManga(initialManga: Manga): androidx.compose.runtime.State<Manga> {
|
fun getManga(initialManga: Manga): androidx.compose.runtime.State<Manga> {
|
||||||
return produceState(initialValue = initialManga) {
|
return produceState(initialValue = initialManga) {
|
||||||
getManga.subscribe(initialManga.url, initialManga.source)
|
getManga.subscribe(initialManga.url, initialManga.source)
|
||||||
.filterNotNull()
|
|
||||||
.collectLatest { manga ->
|
.collectLatest { manga ->
|
||||||
value = manga
|
value = manga
|
||||||
|
// KMK -->
|
||||||
|
?: initialManga
|
||||||
|
// KMK <--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +189,9 @@ abstract class SearchScreenModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
val titles = page.mangas.map {
|
val titles = page.mangas.map {
|
||||||
networkToLocalManga.await(it.toDomainManga(source.id))
|
// KMK -->
|
||||||
|
it.toDomainManga(source.id)
|
||||||
|
// KMK <--
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ import androidx.core.net.toUri
|
||||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||||
import cafe.adriel.voyager.core.model.screenModelScope
|
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.Navigator
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
|
@ -367,12 +366,22 @@ class MangaScreen(
|
||||||
getMangaState = { screenModel.getManga(initialManga = it) },
|
getMangaState = { screenModel.getManga(initialManga = it) },
|
||||||
onRelatedMangasScreenClick = {
|
onRelatedMangasScreenClick = {
|
||||||
if (successState.isRelatedMangasFetched == null) {
|
if (successState.isRelatedMangasFetched == null) {
|
||||||
screenModel.screenModelScope.launchIO { screenModel.fetchRelatedMangasFromSource(onDemand = true) }
|
scope.launchIO { screenModel.fetchRelatedMangasFromSource(onDemand = true) }
|
||||||
}
|
}
|
||||||
showRelatedMangasScreen()
|
showRelatedMangasScreen()
|
||||||
},
|
},
|
||||||
onRelatedMangaClick = { navigator.push(MangaScreen(it.id, true)) },
|
onRelatedMangaClick = {
|
||||||
onRelatedMangaLongClick = { bulkFavoriteScreenModel.addRemoveManga(it, haptic) },
|
scope.launchIO {
|
||||||
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRelatedMangaLongClick = {
|
||||||
|
scope.launchIO {
|
||||||
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
|
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||||
|
}
|
||||||
|
},
|
||||||
onSourceClick = {
|
onSourceClick = {
|
||||||
if (successState.source !is StubSource) {
|
if (successState.source !is StubSource) {
|
||||||
val screen = when {
|
val screen = when {
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,6 @@ import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.distinctUntilChangedBy
|
import kotlinx.coroutines.flow.distinctUntilChangedBy
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
|
||||||
import kotlinx.coroutines.flow.flatMapConcat
|
import kotlinx.coroutines.flow.flatMapConcat
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
@ -191,7 +190,7 @@ class MangaScreenModel(
|
||||||
private val smartSearchMerge: SmartSearchMerge = Injekt.get(),
|
private val smartSearchMerge: SmartSearchMerge = Injekt.get(),
|
||||||
// KMK <--
|
// KMK <--
|
||||||
private val updateMergedSettings: UpdateMergedSettings = Injekt.get(),
|
private val updateMergedSettings: UpdateMergedSettings = Injekt.get(),
|
||||||
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||||
private val deleteMergeById: DeleteMergeById = Injekt.get(),
|
private val deleteMergeById: DeleteMergeById = Injekt.get(),
|
||||||
private val getFlatMetadata: GetFlatMetadataById = Injekt.get(),
|
private val getFlatMetadata: GetFlatMetadataById = Injekt.get(),
|
||||||
private val getPagePreviews: GetPagePreviews = Injekt.get(),
|
private val getPagePreviews: GetPagePreviews = Injekt.get(),
|
||||||
|
|
@ -702,10 +701,12 @@ class MangaScreenModel(
|
||||||
fun getManga(initialManga: Manga): RuntimeState<Manga> {
|
fun getManga(initialManga: Manga): RuntimeState<Manga> {
|
||||||
return produceState(initialValue = initialManga) {
|
return produceState(initialValue = initialManga) {
|
||||||
getManga.subscribe(initialManga.url, initialManga.source)
|
getManga.subscribe(initialManga.url, initialManga.source)
|
||||||
.filterNotNull()
|
|
||||||
.flowWithLifecycle(lifecycle)
|
.flowWithLifecycle(lifecycle)
|
||||||
.collectLatest { manga ->
|
.collectLatest { manga ->
|
||||||
value = manga
|
value = manga
|
||||||
|
// KMK -->
|
||||||
|
?: initialManga
|
||||||
|
// KMK <--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1150,7 +1151,9 @@ class MangaScreenModel(
|
||||||
/* Push found related mangas into collection */
|
/* Push found related mangas into collection */
|
||||||
val relatedManga = RelatedManga.Success.fromPair(pair) { mangaList ->
|
val relatedManga = RelatedManga.Success.fromPair(pair) { mangaList ->
|
||||||
mangaList.map {
|
mangaList.map {
|
||||||
networkToLocalManga.await(it.toDomainManga(state.source.id))
|
// KMK -->
|
||||||
|
it.toDomainManga(state.source.id)
|
||||||
|
// KMK <--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1985,13 +1988,13 @@ sealed interface RelatedManga {
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun List<RelatedManga>.removeDuplicates(manga: Manga): List<RelatedManga> {
|
internal fun List<RelatedManga>.removeDuplicates(manga: Manga): List<RelatedManga> {
|
||||||
val mangaIds = HashSet<Long>().apply { add(manga.id) }
|
val mangaHashes = HashSet<Int>().apply { add(manga.url.hashCode()) }
|
||||||
|
|
||||||
return map { relatedManga ->
|
return map { relatedManga ->
|
||||||
if (relatedManga is Success) {
|
if (relatedManga is Success) {
|
||||||
val stripedList = relatedManga.mangaList.mapNotNull {
|
val stripedList = relatedManga.mangaList.mapNotNull {
|
||||||
if (!mangaIds.contains(it.id)) {
|
if (!mangaHashes.contains(it.url.hashCode())) {
|
||||||
mangaIds.add(it.id)
|
mangaHashes.add(it.url.hashCode())
|
||||||
it
|
it
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import tachiyomi.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
|
|
@ -88,18 +89,24 @@ fun RelatedMangasScreen(
|
||||||
columns = getColumnsPreference(LocalConfiguration.current.orientation),
|
columns = getColumnsPreference(LocalConfiguration.current.orientation),
|
||||||
displayMode = displayMode,
|
displayMode = displayMode,
|
||||||
contentPadding = paddingValues,
|
contentPadding = paddingValues,
|
||||||
onMangaClick = { manga ->
|
onMangaClick = {
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (bulkFavoriteState.selectionMode) {
|
||||||
navigator.push(MangaScreen(manga.id, true))
|
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||||
|
} else {
|
||||||
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMangaLongClick = { manga ->
|
onMangaLongClick = {
|
||||||
if (!bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (!bulkFavoriteState.selectionMode) {
|
||||||
navigator.push(MangaScreen(manga.id, true))
|
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||||
|
} else {
|
||||||
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onKeywordClick = { query ->
|
onKeywordClick = { query ->
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
|
||||||
|
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
|
|
||||||
|
// KMK -->
|
||||||
|
val mangaList = screenModel.mangaPagerFlowFlow.collectAsLazyPagingItems()
|
||||||
|
// KMK <--
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { scrollBehavior ->
|
topBar = { scrollBehavior ->
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
|
@ -75,12 +78,17 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
|
||||||
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
|
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
|
||||||
onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite,
|
onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite,
|
||||||
onSelectAll = {
|
onSelectAll = {
|
||||||
state.mangaDisplayingList.forEach { manga ->
|
mangaList.itemSnapshotList.items
|
||||||
bulkFavoriteScreenModel.select(manga)
|
.map { it.value.first }
|
||||||
}
|
.forEach { manga ->
|
||||||
|
bulkFavoriteScreenModel.select(manga)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onReverseSelection = {
|
onReverseSelection = {
|
||||||
bulkFavoriteScreenModel.reverseSelection(state.mangaDisplayingList.toList())
|
bulkFavoriteScreenModel.reverseSelection(
|
||||||
|
mangaList.itemSnapshotList.items
|
||||||
|
.map { it.value.first },
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -104,7 +112,7 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
BrowseSourceContent(
|
BrowseSourceContent(
|
||||||
source = screenModel.source,
|
source = screenModel.source,
|
||||||
mangaList = screenModel.mangaPagerFlowFlow.collectAsLazyPagingItems(),
|
mangaList = mangaList,
|
||||||
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
||||||
// SY -->
|
// SY -->
|
||||||
ehentaiBrowseDisplayMode = screenModel.ehentaiBrowseDisplayMode,
|
ehentaiBrowseDisplayMode = screenModel.ehentaiBrowseDisplayMode,
|
||||||
|
|
@ -117,20 +125,24 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
|
||||||
onLocalSourceHelpClick = null,
|
onLocalSourceHelpClick = null,
|
||||||
onMangaClick = {
|
onMangaClick = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.toggleSelection(it)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||||
navigator.push(MangaScreen(it.id, true))
|
} else {
|
||||||
|
// KMK <--
|
||||||
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMangaLongClick = { manga ->
|
onMangaLongClick = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
navigator.push(MangaScreen(manga.id, true))
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
navigator.push(MangaScreen(manga.id, true))
|
||||||
scope.launchIO {
|
} else {
|
||||||
|
// KMK <--
|
||||||
val duplicateManga = screenModel.getDuplicateLibraryManga(manga)
|
val duplicateManga = screenModel.getDuplicateLibraryManga(manga)
|
||||||
when {
|
when {
|
||||||
manga.favorite -> screenModel.setDialog(
|
manga.favorite -> screenModel.setDialog(
|
||||||
|
|
@ -150,7 +162,6 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
|
||||||
},
|
},
|
||||||
// KMK -->
|
// KMK -->
|
||||||
selection = bulkFavoriteState.selection,
|
selection = bulkFavoriteState.selection,
|
||||||
browseSourceState = state,
|
|
||||||
// KMK <--
|
// KMK <--
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||||
|
|
@ -25,6 +26,7 @@ import eu.kanade.tachiyomi.ui.browse.ChangeMangasCategoryDialog
|
||||||
import eu.kanade.tachiyomi.ui.browse.RemoveMangaDialog
|
import eu.kanade.tachiyomi.ui.browse.RemoveMangaDialog
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||||
import mihon.presentation.core.util.collectAsLazyPagingItems
|
import mihon.presentation.core.util.collectAsLazyPagingItems
|
||||||
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.i18n.sy.SYMR
|
import tachiyomi.i18n.sy.SYMR
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
|
|
@ -44,7 +46,7 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
val state by screenModel.state.collectAsState()
|
val scope = rememberCoroutineScope()
|
||||||
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
||||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||||
|
|
||||||
|
|
@ -61,6 +63,9 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
||||||
|
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
|
|
||||||
|
// KMK -->
|
||||||
|
val mangaList = screenModel.mangaPagerFlowFlow.collectAsLazyPagingItems()
|
||||||
|
// KMK <--
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { scrollBehavior ->
|
topBar = { scrollBehavior ->
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
|
@ -71,12 +76,17 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
||||||
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
|
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
|
||||||
onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite,
|
onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite,
|
||||||
onSelectAll = {
|
onSelectAll = {
|
||||||
state.mangaDisplayingList.forEach { manga ->
|
mangaList.itemSnapshotList.items
|
||||||
bulkFavoriteScreenModel.select(manga)
|
.map { it.value.first }
|
||||||
}
|
.forEach { manga ->
|
||||||
|
bulkFavoriteScreenModel.select(manga)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onReverseSelection = {
|
onReverseSelection = {
|
||||||
bulkFavoriteScreenModel.reverseSelection(state.mangaDisplayingList.toList())
|
bulkFavoriteScreenModel.reverseSelection(
|
||||||
|
mangaList.itemSnapshotList.items
|
||||||
|
.map { it.value.first },
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -98,7 +108,7 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
BrowseSourceContent(
|
BrowseSourceContent(
|
||||||
source = screenModel.source,
|
source = screenModel.source,
|
||||||
mangaList = screenModel.mangaPagerFlowFlow.collectAsLazyPagingItems(),
|
mangaList = mangaList,
|
||||||
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
||||||
// SY -->
|
// SY -->
|
||||||
ehentaiBrowseDisplayMode = false,
|
ehentaiBrowseDisplayMode = false,
|
||||||
|
|
@ -109,27 +119,32 @@ class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
||||||
onWebViewClick = null,
|
onWebViewClick = null,
|
||||||
onHelpClick = null,
|
onHelpClick = null,
|
||||||
onLocalSourceHelpClick = null,
|
onLocalSourceHelpClick = null,
|
||||||
onMangaClick = { manga ->
|
onMangaClick = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||||
onMangaClick(manga)
|
} else {
|
||||||
|
// KMK <--
|
||||||
|
onMangaClick(manga)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMangaLongClick = { manga ->
|
onMangaLongClick = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (!bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (!bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||||
onMangaClick(manga)
|
} else {
|
||||||
|
// KMK <--
|
||||||
|
onMangaClick(manga)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// KMK -->
|
// KMK -->
|
||||||
selection = bulkFavoriteState.selection,
|
selection = bulkFavoriteState.selection,
|
||||||
browseSourceState = state,
|
|
||||||
// KMK <--
|
// KMK <--
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||||
|
|
@ -26,6 +27,7 @@ import eu.kanade.tachiyomi.ui.browse.ChangeMangasCategoryDialog
|
||||||
import eu.kanade.tachiyomi.ui.browse.RemoveMangaDialog
|
import eu.kanade.tachiyomi.ui.browse.RemoveMangaDialog
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen
|
import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen
|
||||||
import mihon.presentation.core.util.collectAsLazyPagingItems
|
import mihon.presentation.core.util.collectAsLazyPagingItems
|
||||||
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||||
|
|
@ -43,7 +45,7 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
// KMK -->
|
// KMK -->
|
||||||
val state by screenModel.state.collectAsState()
|
val scope = rememberCoroutineScope()
|
||||||
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
||||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||||
|
|
||||||
|
|
@ -60,6 +62,9 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
||||||
|
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
|
|
||||||
|
// KMK -->
|
||||||
|
val mangaList = screenModel.mangaPagerFlowFlow.collectAsLazyPagingItems()
|
||||||
|
// KMK <--
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { scrollBehavior ->
|
topBar = { scrollBehavior ->
|
||||||
// KMK -->
|
// KMK -->
|
||||||
|
|
@ -70,12 +75,17 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
||||||
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
|
onClickClearSelection = bulkFavoriteScreenModel::toggleSelectionMode,
|
||||||
onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite,
|
onChangeCategoryClick = bulkFavoriteScreenModel::addFavorite,
|
||||||
onSelectAll = {
|
onSelectAll = {
|
||||||
state.mangaDisplayingList.forEach { manga ->
|
mangaList.itemSnapshotList.items
|
||||||
bulkFavoriteScreenModel.select(manga)
|
.map { it.value.first }
|
||||||
}
|
.forEach { manga ->
|
||||||
|
bulkFavoriteScreenModel.select(manga)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onReverseSelection = {
|
onReverseSelection = {
|
||||||
bulkFavoriteScreenModel.reverseSelection(state.mangaDisplayingList.toList())
|
bulkFavoriteScreenModel.reverseSelection(
|
||||||
|
mangaList.itemSnapshotList.items
|
||||||
|
.map { it.value.first },
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -97,7 +107,7 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
BrowseSourceContent(
|
BrowseSourceContent(
|
||||||
source = screenModel.source,
|
source = screenModel.source,
|
||||||
mangaList = screenModel.mangaPagerFlowFlow.collectAsLazyPagingItems(),
|
mangaList = mangaList,
|
||||||
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
||||||
// SY -->
|
// SY -->
|
||||||
ehentaiBrowseDisplayMode = false,
|
ehentaiBrowseDisplayMode = false,
|
||||||
|
|
@ -108,25 +118,30 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
||||||
onWebViewClick = null,
|
onWebViewClick = null,
|
||||||
onHelpClick = null,
|
onHelpClick = null,
|
||||||
onLocalSourceHelpClick = null,
|
onLocalSourceHelpClick = null,
|
||||||
onMangaClick = { manga ->
|
onMangaClick = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
} else {
|
if (bulkFavoriteState.selectionMode) {
|
||||||
// KMK <--
|
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||||
onMangaClick(manga)
|
} else {
|
||||||
|
// KMK <--
|
||||||
|
onMangaClick(manga)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMangaLongClick = { manga ->
|
onMangaLongClick = {
|
||||||
// KMK -->
|
// KMK -->
|
||||||
if (!bulkFavoriteState.selectionMode) {
|
scope.launchIO {
|
||||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||||
|
if (!bulkFavoriteState.selectionMode) {
|
||||||
|
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// KMK <--
|
// KMK <--
|
||||||
},
|
},
|
||||||
// KMK -->
|
// KMK -->
|
||||||
selection = bulkFavoriteState.selection,
|
selection = bulkFavoriteState.selection,
|
||||||
browseSourceState = state,
|
|
||||||
// KMK <--
|
// KMK <--
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,14 @@ class NetworkToLocalManga(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KMK -->
|
||||||
|
suspend fun getLocal(manga: Manga): Manga = if (manga.id <= 0) {
|
||||||
|
await(manga)
|
||||||
|
} else {
|
||||||
|
manga
|
||||||
|
}
|
||||||
|
// KMK <--
|
||||||
|
|
||||||
private suspend fun getManga(url: String, sourceId: Long): Manga? {
|
private suspend fun getManga(url: String, sourceId: Long): Manga? {
|
||||||
return mangaRepository.getMangaByUrlAndSourceId(url, sourceId)
|
return mangaRepository.getMangaByUrlAndSourceId(url, sourceId)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue