chore(network-local-manga): Reintroduce (in-memory) fast browsing (#909)
* measure time
* Revert "Revert "Fast browsing (#612)""
This reverts commit d23130b317.
* Fix networkToLocal for bulk-selection selectAll/reverseSelection
* fix comments
This commit is contained in:
parent
7dd57c54bc
commit
3310784faf
29 changed files with 431 additions and 170 deletions
|
|
@ -6,6 +6,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import eu.kanade.domain.source.model.installedExtension
|
||||
import eu.kanade.presentation.browse.components.GlobalSearchCardRow
|
||||
|
|
@ -21,6 +22,7 @@ import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchScreenModel
|
|||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.domain.source.model.Source as DomainSource
|
||||
|
|
@ -43,6 +45,7 @@ fun GlobalSearchScreen(
|
|||
// KMK <--
|
||||
) {
|
||||
// KMK -->
|
||||
val scope = rememberCoroutineScope()
|
||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||
// KMK <--
|
||||
|
||||
|
|
@ -59,13 +62,24 @@ fun GlobalSearchScreen(
|
|||
state.filteredItems.values
|
||||
.filterIsInstance<SearchItemResult.Success>()
|
||||
.flatMap { it.result }
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it)
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
}
|
||||
}
|
||||
},
|
||||
onReverseSelection = {
|
||||
state.filteredItems.values
|
||||
.filterIsInstance<SearchItemResult.Success>()
|
||||
.flatMap { it.result }
|
||||
.let { bulkFavoriteScreenModel.reverseSelection(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.reverseSelection(
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
|
||||
import eu.kanade.presentation.components.BulkSelectionToolbar
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
|
|
@ -11,6 +12,7 @@ import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel
|
|||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchScreenModel
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
|
||||
|
|
@ -33,6 +35,7 @@ fun MigrateSearchScreen(
|
|||
// KMK <--
|
||||
) {
|
||||
// KMK -->
|
||||
val scope = rememberCoroutineScope()
|
||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||
// KMK <--
|
||||
|
||||
|
|
@ -49,13 +52,24 @@ fun MigrateSearchScreen(
|
|||
state.filteredItems.values
|
||||
.filterIsInstance<SearchItemResult.Success>()
|
||||
.flatMap { it.result }
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it)
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
}
|
||||
}
|
||||
},
|
||||
onReverseSelection = {
|
||||
state.filteredItems.values
|
||||
.filterIsInstance<SearchItemResult.Success>()
|
||||
.flatMap { it.result }
|
||||
.let { bulkFavoriteScreenModel.reverseSelection(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.reverseSelection(
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.presentation.browse.components.BrowseSourceFloatingActionButton
|
||||
|
|
@ -26,6 +27,7 @@ import eu.kanade.presentation.components.SearchToolbar
|
|||
import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.source.model.FeedSavedSearch
|
||||
import tachiyomi.domain.source.model.SavedSearch
|
||||
|
|
@ -112,6 +114,7 @@ fun SourceFeedScreen(
|
|||
// KMK <--
|
||||
) {
|
||||
// KMK -->
|
||||
val scope = rememberCoroutineScope()
|
||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||
// KMK <--
|
||||
|
||||
|
|
@ -127,12 +130,23 @@ fun SourceFeedScreen(
|
|||
onSelectAll = {
|
||||
items.mapNotNull { it.results }
|
||||
.flatten()
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it)
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
}
|
||||
}
|
||||
},
|
||||
onReverseSelection = {
|
||||
items.mapNotNull { it.results }
|
||||
.flatten()
|
||||
.let { bulkFavoriteScreenModel.reverseSelection(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.reverseSelection(
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ fun RelatedMangasComfortableGrid(
|
|||
)
|
||||
}
|
||||
items(
|
||||
key = { "related-comfort-${relatedManga.mangaList[it].id}" },
|
||||
key = { "related-comfort-${relatedManga.mangaList[it].url.hashCode()}" },
|
||||
count = relatedManga.mangaList.size,
|
||||
) { index ->
|
||||
val manga by getManga(relatedManga.mangaList[index])
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ fun RelatedMangasCompactGrid(
|
|||
)
|
||||
}
|
||||
items(
|
||||
key = { "related-compact-${relatedManga.mangaList[it].id}" },
|
||||
key = { "related-compact-${relatedManga.mangaList[it].url.hashCode()}" },
|
||||
count = relatedManga.mangaList.size,
|
||||
) { index ->
|
||||
val manga by getManga(relatedManga.mangaList[index])
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ fun RelatedMangasList(
|
|||
)
|
||||
}
|
||||
items(
|
||||
key = { "related-list-${relatedManga.mangaList[it].id}" },
|
||||
key = { "related-list-${relatedManga.mangaList[it].url.hashCode()}" },
|
||||
count = relatedManga.mangaList.size,
|
||||
) { index ->
|
||||
val manga by getManga(relatedManga.mangaList[index])
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import eu.kanade.tachiyomi.ui.browse.feed.FeedScreenModel
|
|||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.TabText
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
|
|
@ -68,14 +69,25 @@ fun TabbedScreen(
|
|||
feedState.items?.let { result ->
|
||||
result.mapNotNull { it.results }
|
||||
.flatten()
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it)
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onReverseSelection = {
|
||||
feedState.items?.let { result ->
|
||||
result.mapNotNull { it.results }
|
||||
.flatten()
|
||||
.let { bulkFavoriteScreenModel.reverseSelection(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.reverseSelection(
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ fun RelatedMangaCardRow(
|
|||
contentPadding = PaddingValues(MaterialTheme.padding.small),
|
||||
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)
|
||||
MangaItem(
|
||||
title = manga.title,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import tachiyomi.domain.category.model.Category
|
|||
import tachiyomi.domain.chapter.interactor.SetMangaDefaultChapterFlags
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga
|
||||
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||
import tachiyomi.domain.manga.model.toMangaUpdate
|
||||
|
|
@ -53,6 +54,10 @@ class BulkFavoriteScreenModel(
|
|||
private val coverCache: CoverCache = Injekt.get(),
|
||||
private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(),
|
||||
private val addTracks: AddTracks = Injekt.get(),
|
||||
|
||||
// KMK -->
|
||||
val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||
// KMK <--
|
||||
) : StateScreenModel<BulkFavoriteScreenModel.State>(initialState) {
|
||||
|
||||
fun backHandler() {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ open class FeedScreenModel(
|
|||
val sourceManager: SourceManager = Injekt.get(),
|
||||
val sourcePreferences: SourcePreferences = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||
val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||
getFeedSavedSearchGlobal: GetFeedSavedSearchGlobal = Injekt.get(),
|
||||
private val getSavedSearchGlobalFeed: GetSavedSearchGlobalFeed = Injekt.get(),
|
||||
private val countFeedSavedSearchGlobal: CountFeedSavedSearchGlobal = Injekt.get(),
|
||||
|
|
@ -304,8 +304,8 @@ open class FeedScreenModel(
|
|||
results = page
|
||||
.map { it.toDomainManga(itemUI.source!!.id) }
|
||||
.distinctBy { it.url }
|
||||
.let { networkToLocalManga(it) }
|
||||
// KMK -->
|
||||
// .let { networkToLocalManga(it) }
|
||||
.filter { !hideInLibraryFeedItems.get() || !it.favorite },
|
||||
// KMK <--
|
||||
)
|
||||
|
|
@ -343,8 +343,11 @@ open class FeedScreenModel(
|
|||
return produceState(initialValue = initialManga) {
|
||||
getManga.subscribe(initialManga.url, initialManga.source)
|
||||
.collectLatest { manga ->
|
||||
if (manga == null) return@collectLatest
|
||||
/* KMK --> if (manga == null) return@collectLatest KMK <-- */
|
||||
value = manga
|
||||
// KMK -->
|
||||
?: initialManga
|
||||
// KMK <--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import androidx.compose.runtime.LaunchedEffect
|
|||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
|
|
@ -36,6 +37,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
|||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.domain.source.interactor.GetRemoteManga
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.i18n.kmk.KMR
|
||||
|
|
@ -53,6 +55,7 @@ fun Screen.feedTab(
|
|||
val state by screenModel.state.collectAsState()
|
||||
|
||||
// KMK -->
|
||||
val scope = rememberCoroutineScope()
|
||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||
val showingFeedOrderScreen = rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
|
|
@ -165,21 +168,27 @@ fun Screen.feedTab(
|
|||
// KMK -->
|
||||
onLongClickFeed = screenModel::openActionsDialog,
|
||||
// KMK <--
|
||||
onClickManga = { manga ->
|
||||
onClickManga = {
|
||||
// KMK -->
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
}
|
||||
}
|
||||
},
|
||||
// KMK -->
|
||||
onLongClickManga = { manga ->
|
||||
if (!bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||
} else {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
onLongClickManga = {
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (!bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||
} else {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
}
|
||||
}
|
||||
},
|
||||
selection = bulkFavoriteState.selection,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.activity.compose.BackHandler
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
|
|
@ -13,6 +14,7 @@ import eu.kanade.presentation.util.Screen
|
|||
import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListScreen
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
|
||||
/**
|
||||
* Manual search [validSources] for manga to migrate to.
|
||||
|
|
@ -30,6 +32,7 @@ class MigrateSearchScreen(private val mangaId: Long, private val validSources: L
|
|||
val dialogState by dialogScreenModel.state.collectAsState()
|
||||
|
||||
// KMK -->
|
||||
val scope = rememberCoroutineScope()
|
||||
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||
|
||||
|
|
@ -52,23 +55,33 @@ class MigrateSearchScreen(private val mangaId: Long, private val validSources: L
|
|||
navigator.push(SourceSearchScreen(dialogState.manga!!, it.id, state.searchQuery))
|
||||
// SY <--
|
||||
},
|
||||
onClickItem = { manga ->
|
||||
onClickItem = {
|
||||
// KMK -->
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else
|
||||
// KMK <--
|
||||
{
|
||||
// SY -->
|
||||
navigator.items
|
||||
.filterIsInstance<MigrationListScreen>()
|
||||
.last()
|
||||
.newSelectedItem = mangaId to manga.id
|
||||
navigator.popUntil { it is MigrationListScreen }
|
||||
// SY <--
|
||||
}
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else
|
||||
// KMK <--
|
||||
{
|
||||
// SY -->
|
||||
navigator.items
|
||||
.filterIsInstance<MigrationListScreen>()
|
||||
.last()
|
||||
.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 -->
|
||||
bulkFavoriteScreenModel = bulkFavoriteScreenModel,
|
||||
hasPinnedSources = screenModel.hasPinnedSources(),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
|
|
@ -33,6 +34,7 @@ import eu.kanade.tachiyomi.util.system.toast
|
|||
import kotlinx.collections.immutable.persistentListOf
|
||||
import mihon.presentation.core.util.collectAsLazyPagingItems
|
||||
import tachiyomi.core.common.Constants
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.sy.SYMR
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
|
|
@ -66,6 +68,7 @@ data class SourceSearchScreen(
|
|||
|
||||
// KMK -->
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||
|
|
@ -89,12 +92,23 @@ data class SourceSearchScreen(
|
|||
onSelectAll = {
|
||||
mangaList.itemSnapshotList.items
|
||||
.map { it.value.first }
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it)
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
}
|
||||
}
|
||||
},
|
||||
onReverseSelection = {
|
||||
mangaList.itemSnapshotList.items
|
||||
.map { it.value.first }
|
||||
.let { bulkFavoriteScreenModel.reverseSelection(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.reverseSelection(
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
|
@ -161,16 +175,26 @@ data class SourceSearchScreen(
|
|||
},
|
||||
onHelpClick = { uriHandler.openUri(Constants.URL_HELP) },
|
||||
onLocalSourceHelpClick = { uriHandler.openUri(LocalSource.HELP_URL) },
|
||||
onMangaClick = { manga ->
|
||||
onMangaClick = {
|
||||
// KMK -->
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
openMigrateDialog(manga)
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(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 -->
|
||||
selection = bulkFavoriteState.selection,
|
||||
// KMK <--
|
||||
|
|
|
|||
|
|
@ -202,12 +202,23 @@ data class BrowseSourceScreen(
|
|||
onSelectAll = {
|
||||
mangaList.itemSnapshotList.items
|
||||
.map { it.value.first }
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it)
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
}
|
||||
}
|
||||
},
|
||||
onReverseSelection = {
|
||||
mangaList.itemSnapshotList.items
|
||||
.map { it.value.first }
|
||||
.let { bulkFavoriteScreenModel.reverseSelection(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.reverseSelection(
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
|
@ -356,32 +367,36 @@ data class BrowseSourceScreen(
|
|||
onWebViewClick = onWebViewClick,
|
||||
onHelpClick = { uriHandler.openUri(Constants.URL_HELP) },
|
||||
onLocalSourceHelpClick = onHelpClick,
|
||||
onMangaClick = { manga ->
|
||||
onMangaClick = {
|
||||
// KMK -->
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
navigator.push(
|
||||
MangaScreen(
|
||||
mangaId = manga.id,
|
||||
// KMK -->
|
||||
// Finding the entry to be merged to, so we don't want to expand description
|
||||
// so that user can see the `Merge to another` button
|
||||
fromSource = smartSearchConfig == null,
|
||||
// KMK <--
|
||||
smartSearchConfig = smartSearchConfig,
|
||||
),
|
||||
)
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
navigator.push(
|
||||
MangaScreen(
|
||||
mangaId = manga.id,
|
||||
// KMK -->
|
||||
// Finding the entry to be merged to, so we don't want to expand description
|
||||
// so that user can see the `Merge to another` button
|
||||
fromSource = smartSearchConfig == null,
|
||||
// KMK <--
|
||||
smartSearchConfig = smartSearchConfig,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
onMangaLongClick = { manga ->
|
||||
onMangaLongClick = {
|
||||
// KMK -->
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
} else {
|
||||
// KMK <--
|
||||
scope.launchIO {
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
} else {
|
||||
// KMK <--
|
||||
val duplicates = screenModel.getDuplicateLibraryManga(manga)
|
||||
when {
|
||||
manga.favorite -> screenModel.setDialog(BrowseSourceScreenModel.Dialog.RemoveManga(manga))
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ import tachiyomi.domain.library.service.LibraryPreferences
|
|||
import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga
|
||||
import tachiyomi.domain.manga.interactor.GetFlatMetadataById
|
||||
import tachiyomi.domain.manga.interactor.GetManga
|
||||
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||
import tachiyomi.domain.manga.model.toMangaUpdate
|
||||
|
|
@ -114,6 +115,9 @@ open class BrowseSourceScreenModel(
|
|||
private val extensionManager: ExtensionManager = Injekt.get(),
|
||||
// KMK <--
|
||||
|
||||
// KMK -->
|
||||
val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||
// KMK <--
|
||||
// SY -->
|
||||
unsortedPreferences: UnsortedPreferences = Injekt.get(),
|
||||
uiPreferences: UiPreferences = Injekt.get(),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.LaunchedEffect
|
|||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
|
|
@ -39,6 +40,7 @@ import exh.md.follows.MangaDexFollowsScreen
|
|||
import exh.source.anyIs
|
||||
import exh.source.isEhBasedSource
|
||||
import exh.util.nullIfBlank
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.domain.UnsortedPreferences
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.source.interactor.GetRemoteManga
|
||||
|
|
@ -65,6 +67,7 @@ class SourceFeedScreen(val sourceId: Long) : Screen() {
|
|||
val context = LocalContext.current
|
||||
|
||||
// KMK -->
|
||||
val scope = rememberCoroutineScope()
|
||||
screenModel.source.let {
|
||||
if (it is StubSource) {
|
||||
MissingSourceScreen(
|
||||
|
|
@ -123,13 +126,16 @@ class SourceFeedScreen(val sourceId: Long) : Screen() {
|
|||
// onClickDelete = screenModel::openDeleteFeed,
|
||||
onLongClickFeed = screenModel::openActionsDialog,
|
||||
// KMK <--
|
||||
onClickManga = { manga ->
|
||||
onClickManga = {
|
||||
// KMK -->
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
onMangaClick(navigator, manga)
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
onMangaClick(navigator, manga)
|
||||
}
|
||||
}
|
||||
},
|
||||
onClickSearch = { onSearchClick(navigator, screenModel.source, it) },
|
||||
|
|
@ -164,11 +170,14 @@ class SourceFeedScreen(val sourceId: Long) : Screen() {
|
|||
.filterIsInstance<SourceFeedUI.SourceSavedSearch>()
|
||||
.isNotEmpty()
|
||||
},
|
||||
onLongClickManga = { manga ->
|
||||
if (!bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||
} else {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
onLongClickManga = {
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (!bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||
} else {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
}
|
||||
}
|
||||
},
|
||||
bulkFavoriteScreenModel = bulkFavoriteScreenModel,
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ open class SourceFeedScreenModel(
|
|||
uiPreferences: UiPreferences = Injekt.get(),
|
||||
private val sourceManager: SourceManager = 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 getSavedSearchBySourceIdFeed: GetSavedSearchBySourceIdFeed = Injekt.get(),
|
||||
private val countFeedSavedSearchBySourceId: CountFeedSavedSearchBySourceId = Injekt.get(),
|
||||
|
|
@ -250,7 +250,7 @@ open class SourceFeedScreenModel(
|
|||
val titles = withIOContext {
|
||||
page.map { it.toDomainManga(source.id) }
|
||||
.distinctBy { it.url }
|
||||
.let { networkToLocalManga(it) }
|
||||
/* KMK --> .let { networkToLocalManga(it) } KMK <-- */
|
||||
}
|
||||
|
||||
mutableState.update { state ->
|
||||
|
|
@ -284,8 +284,11 @@ open class SourceFeedScreenModel(
|
|||
return produceState(initialValue = initialManga) {
|
||||
getManga.subscribe(initialManga.url, initialManga.source)
|
||||
.collectLatest { manga ->
|
||||
if (manga == null) return@collectLatest
|
||||
/* KMK --> if (manga == null) return@collectLatest KMK <-- */
|
||||
value = manga
|
||||
// KMK -->
|
||||
?: initialManga
|
||||
// KMK <--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.collectAsState
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
|
|
@ -19,6 +20,7 @@ import eu.kanade.presentation.util.Screen
|
|||
import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
class GlobalSearchScreen(
|
||||
|
|
@ -47,6 +49,7 @@ class GlobalSearchScreen(
|
|||
}
|
||||
|
||||
// KMK -->
|
||||
val scope = rememberCoroutineScope()
|
||||
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||
|
||||
|
|
@ -66,7 +69,12 @@ class GlobalSearchScreen(
|
|||
is SearchItemResult.Success -> {
|
||||
val manga = result.result.singleOrNull()
|
||||
if (manga != null) {
|
||||
navigator.replace(MangaScreen(manga.id, true))
|
||||
// KMK -->
|
||||
scope.launchIO {
|
||||
val localManga = screenModel.networkToLocalManga.getLocal(manga)
|
||||
// KMK <--
|
||||
navigator.replace(MangaScreen(localManga.id, true))
|
||||
}
|
||||
} else {
|
||||
// Backoff to result screen
|
||||
showSingleLoadingScreen = false
|
||||
|
|
@ -87,22 +95,28 @@ class GlobalSearchScreen(
|
|||
onClickSource = {
|
||||
navigator.push(BrowseSourceScreen(it.id, state.searchQuery))
|
||||
},
|
||||
onClickItem = { manga ->
|
||||
onClickItem = {
|
||||
// KMK -->
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
}
|
||||
}
|
||||
},
|
||||
onLongClickItem = { manga ->
|
||||
onLongClickItem = {
|
||||
// KMK -->
|
||||
if (!bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||
} else {
|
||||
// KMK <--
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (!bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||
} else {
|
||||
// KMK <--
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
}
|
||||
}
|
||||
},
|
||||
// KMK -->
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import kotlinx.coroutines.asCoroutineDispatcher
|
|||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -39,7 +39,7 @@ abstract class SearchScreenModel(
|
|||
sourcePreferences: SourcePreferences = Injekt.get(),
|
||||
private val sourceManager: SourceManager = 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 preferences: SourcePreferences = Injekt.get(),
|
||||
) : StateScreenModel<SearchScreenModel.State>(initialState) {
|
||||
|
|
@ -83,9 +83,12 @@ abstract class SearchScreenModel(
|
|||
fun getManga(initialManga: Manga): androidx.compose.runtime.State<Manga> {
|
||||
return produceState(initialValue = initialManga) {
|
||||
getManga.subscribe(initialManga.url, initialManga.source)
|
||||
.filterNotNull()
|
||||
/* KMK --> .filterNotNull() KMK <-- */
|
||||
.collectLatest { manga ->
|
||||
value = manga
|
||||
// KMK -->
|
||||
?: initialManga
|
||||
// KMK <--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -189,7 +192,7 @@ abstract class SearchScreenModel(
|
|||
val titles = page.mangas
|
||||
.map { it.toDomainManga(source.id) }
|
||||
.distinctBy { it.url }
|
||||
.let { networkToLocalManga(it) }
|
||||
/* KMK --> .let { networkToLocalManga(it) } KMK <-- */
|
||||
|
||||
if (isActive) {
|
||||
updateItem(source, SearchItemResult.Success(titles))
|
||||
|
|
|
|||
|
|
@ -389,8 +389,18 @@ class MangaScreen(
|
|||
}
|
||||
showRelatedMangasScreen()
|
||||
},
|
||||
onRelatedMangaClick = { navigator.push(MangaScreen(it.id, true)) },
|
||||
onRelatedMangaLongClick = { bulkFavoriteScreenModel.addRemoveManga(it, haptic) },
|
||||
onRelatedMangaClick = {
|
||||
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 = {
|
||||
if (successState.source !is StubSource) {
|
||||
val screen = when {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ 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
|
||||
|
|
@ -195,7 +194,7 @@ class MangaScreenModel(
|
|||
private val smartSearchMerge: SmartSearchMerge = Injekt.get(),
|
||||
// KMK <--
|
||||
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 getFlatMetadata: GetFlatMetadataById = Injekt.get(),
|
||||
private val getPagePreviews: GetPagePreviews = Injekt.get(),
|
||||
|
|
@ -705,10 +704,13 @@ class MangaScreenModel(
|
|||
fun getManga(initialManga: Manga): RuntimeState<Manga> {
|
||||
return produceState(initialValue = initialManga) {
|
||||
getManga.subscribe(initialManga.url, initialManga.source)
|
||||
.filterNotNull()
|
||||
/* KMK --> .filterNotNull() KMK <-- */
|
||||
.flowWithLifecycle(lifecycle)
|
||||
.collectLatest { manga ->
|
||||
value = manga
|
||||
// KMK -->
|
||||
?: initialManga
|
||||
// KMK <--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1155,7 +1157,7 @@ class MangaScreenModel(
|
|||
mangaList
|
||||
.map { it.toDomainManga(state.source.id) }
|
||||
.distinctBy { it.url }
|
||||
.let { networkToLocalManga(it) }
|
||||
/* KMK --> .let { networkToLocalManga(it) } KMK <-- */
|
||||
}
|
||||
|
||||
updateSuccessState { successState ->
|
||||
|
|
@ -2008,14 +2010,14 @@ sealed interface 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 ->
|
||||
if (relatedManga is Success) {
|
||||
Success(
|
||||
relatedManga.keyword,
|
||||
relatedManga.mangaList
|
||||
.filter { mangaIds.add(it.id) },
|
||||
.filter { mangaHashes.add(it.url.hashCode()) },
|
||||
)
|
||||
} else {
|
||||
relatedManga
|
||||
|
|
|
|||
|
|
@ -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.globalsearch.GlobalSearchScreen
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import uy.kohesive.injekt.Injekt
|
||||
|
|
@ -57,14 +58,25 @@ fun RelatedMangasScreen(
|
|||
successState.relatedMangasSorted?.let { result ->
|
||||
result.map { it as RelatedManga.Success }
|
||||
.flatMap { it.mangaList }
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it)
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onReverseSelection = {
|
||||
successState.relatedMangasSorted?.let { result ->
|
||||
result.map { it as RelatedManga.Success }
|
||||
.flatMap { it.mangaList }
|
||||
.let { bulkFavoriteScreenModel.reverseSelection(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.reverseSelection(
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
@ -88,18 +100,24 @@ fun RelatedMangasScreen(
|
|||
columns = getColumnsPreference(LocalConfiguration.current.orientation),
|
||||
displayMode = displayMode,
|
||||
contentPadding = paddingValues,
|
||||
onMangaClick = { manga ->
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
onMangaClick = {
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
}
|
||||
}
|
||||
},
|
||||
onMangaLongClick = { manga ->
|
||||
if (!bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||
} else {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
onMangaLongClick = {
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (!bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||
} else {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
}
|
||||
}
|
||||
},
|
||||
onKeywordClick = { query ->
|
||||
|
|
|
|||
|
|
@ -77,12 +77,23 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
|
|||
onSelectAll = {
|
||||
mangaList.itemSnapshotList.items
|
||||
.map { it.value.first }
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it)
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
}
|
||||
}
|
||||
},
|
||||
onReverseSelection = {
|
||||
mangaList.itemSnapshotList.items
|
||||
.map { it.value.first }
|
||||
.let { bulkFavoriteScreenModel.reverseSelection(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.reverseSelection(
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
|
@ -117,22 +128,26 @@ class MangaDexFollowsScreen(private val sourceId: Long) : Screen() {
|
|||
onWebViewClick = null,
|
||||
onHelpClick = null,
|
||||
onLocalSourceHelpClick = null,
|
||||
onMangaClick = { manga ->
|
||||
onMangaClick = {
|
||||
// KMK -->
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
}
|
||||
}
|
||||
},
|
||||
onMangaLongClick = { manga ->
|
||||
onMangaLongClick = {
|
||||
// KMK -->
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
} else {
|
||||
// KMK <--
|
||||
scope.launchIO {
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
navigator.push(MangaScreen(manga.id, true))
|
||||
} else {
|
||||
// KMK <--
|
||||
val duplicates = screenModel.getDuplicateLibraryManga(manga)
|
||||
when {
|
||||
manga.favorite -> screenModel.setDialog(BrowseSourceScreenModel.Dialog.RemoveManga(manga))
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
|
|
@ -24,6 +25,7 @@ import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen
|
|||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||
import mihon.presentation.core.util.collectAsLazyPagingItems
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
|
@ -50,6 +52,7 @@ class BrowseRecommendsScreen(
|
|||
}
|
||||
|
||||
// KMK -->
|
||||
val scope = rememberCoroutineScope()
|
||||
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||
|
||||
|
|
@ -94,12 +97,23 @@ class BrowseRecommendsScreen(
|
|||
onSelectAll = {
|
||||
mangaList.itemSnapshotList.items
|
||||
.map { it.value.first }
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it)
|
||||
.forEach { bulkFavoriteScreenModel.select(it) }
|
||||
}
|
||||
}
|
||||
},
|
||||
onReverseSelection = {
|
||||
mangaList.itemSnapshotList.items
|
||||
.map { it.value.first }
|
||||
.let { bulkFavoriteScreenModel.reverseSelection(it) }
|
||||
.let {
|
||||
scope.launchIO {
|
||||
bulkFavoriteScreenModel.reverseSelection(
|
||||
bulkFavoriteScreenModel.networkToLocalManga.getLocal(it),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
|
@ -139,23 +153,37 @@ class BrowseRecommendsScreen(
|
|||
onWebViewClick = null,
|
||||
onHelpClick = null,
|
||||
onLocalSourceHelpClick = null,
|
||||
onMangaClick = { manga ->
|
||||
onMangaClick = {
|
||||
// KMK -->
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
if (isExternalSource) {
|
||||
onClickItem(it)
|
||||
} else {
|
||||
// KMK <--
|
||||
onClickItem(manga)
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.toggleSelection(manga)
|
||||
} else {
|
||||
// KMK <--
|
||||
onClickItem(manga)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onMangaLongClick = { manga ->
|
||||
onMangaLongClick = {
|
||||
// KMK -->
|
||||
if (!bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||
if (isExternalSource) {
|
||||
onLongClickItem(it)
|
||||
} else {
|
||||
onLongClickItem(manga)
|
||||
scope.launchIO {
|
||||
val manga = screenModel.networkToLocalManga.getLocal(it)
|
||||
if (!bulkFavoriteState.selectionMode) {
|
||||
bulkFavoriteScreenModel.addRemoveManga(manga, haptic)
|
||||
} else {
|
||||
onLongClickItem(manga)
|
||||
}
|
||||
}
|
||||
// KMK <--
|
||||
}
|
||||
// KMK <--
|
||||
},
|
||||
// KMK -->
|
||||
selection = bulkFavoriteState.selection,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.activity.compose.BackHandler
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
|
|
@ -17,6 +18,7 @@ import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen
|
|||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||
import exh.recs.components.RecommendsScreen
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
|
|
@ -38,6 +40,7 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
|||
val state by screenModel.state.collectAsState()
|
||||
|
||||
// KMK -->
|
||||
val scope = rememberCoroutineScope()
|
||||
val bulkFavoriteScreenModel = rememberScreenModel { BulkFavoriteScreenModel() }
|
||||
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
|
||||
|
||||
|
|
@ -49,12 +52,21 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
|||
// KMK <--
|
||||
|
||||
val onClickItem = { manga: Manga ->
|
||||
navigator.push(
|
||||
when (manga.source) {
|
||||
RECOMMENDS_SOURCE -> SourcesScreen(SourcesScreen.SmartSearchConfig(manga.ogTitle))
|
||||
else -> MangaScreen(manga.id, true)
|
||||
},
|
||||
)
|
||||
when (manga.source) {
|
||||
RECOMMENDS_SOURCE -> navigator.push(
|
||||
SourcesScreen(SourcesScreen.SmartSearchConfig(manga.ogTitle)),
|
||||
)
|
||||
else -> {
|
||||
// KMK -->
|
||||
scope.launchIO {
|
||||
val localManga = screenModel.networkToLocalManga.getLocal(manga)
|
||||
navigator.push(
|
||||
// KMK <--
|
||||
MangaScreen(localManga.id, true),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val onLongClickItem = { manga: Manga ->
|
||||
|
|
@ -62,11 +74,13 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {
|
|||
RECOMMENDS_SOURCE -> WebViewActivity.newIntent(context, manga.url, title = manga.title).let(context::startActivity)
|
||||
else -> {
|
||||
// KMK -->
|
||||
// Add to favorite
|
||||
bulkFavoriteScreenModel.addRemoveManga(
|
||||
manga,
|
||||
haptic,
|
||||
)
|
||||
scope.launchIO {
|
||||
val localManga = screenModel.networkToLocalManga.getLocal(manga)
|
||||
bulkFavoriteScreenModel.addRemoveManga(
|
||||
localManga,
|
||||
haptic,
|
||||
)
|
||||
}
|
||||
// KMK <--
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ open class RecommendsScreenModel(
|
|||
val mangaId: Long,
|
||||
val sourceId: Long,
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
protected val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||
val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||
) : StateScreenModel<RecommendsScreenModel.State>(State()) {
|
||||
|
||||
// KMK -->
|
||||
|
|
@ -78,14 +78,14 @@ open class RecommendsScreenModel(
|
|||
}
|
||||
|
||||
val recSourceId = recSource.associatedSourceId
|
||||
val titles = if (recSourceId != null) {
|
||||
// KMK -->
|
||||
val titles = page.mangas.map {
|
||||
// If the recommendation is associated with a source, resolve it
|
||||
page.mangas.map { it.toDomainManga(recSourceId) }
|
||||
.let { networkToLocalManga(it) }
|
||||
} else {
|
||||
// Otherwise, skip this step. The user will be prompted to choose a source via SmartSearch
|
||||
page.mangas.map { it.toDomainManga(RECOMMENDS_SOURCE) }
|
||||
it.toDomainManga(recSourceId ?: RECOMMENDS_SOURCE)
|
||||
/* KMK --> .let { networkToLocalManga(it) } KMK <-- */
|
||||
}
|
||||
// KMK <--
|
||||
.distinctBy { it.url }
|
||||
|
||||
if (isActive) {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ abstract class EHentaiPagingSource(override val source: CatalogueSource) : BaseS
|
|||
val manga = mangasPage.mangas
|
||||
.map { it.toDomainManga(source.id) }
|
||||
.filter { seenManga.add(it.url) }
|
||||
.let { networkToLocalManga(it) }
|
||||
/* KMK --> .let { networkToLocalManga(it) } KMK <-- */
|
||||
// SY -->
|
||||
.mapIndexed { index, manga -> manga to metadata.getOrNull(index) }
|
||||
// SY <--
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ abstract class BaseSourcePagingSource(
|
|||
val manga = mangasPage.mangas
|
||||
.map { it.toDomainManga(source!!.id) }
|
||||
.filter { seenManga.add(it.url) }
|
||||
.let { networkToLocalManga(it) }
|
||||
/* KMK --> .let { networkToLocalManga(it) } KMK <-- */
|
||||
// SY -->
|
||||
.mapIndexed { index, manga -> manga to metadata.getOrNull(index) }
|
||||
// SY <--
|
||||
|
|
|
|||
|
|
@ -14,4 +14,22 @@ class NetworkToLocalManga(
|
|||
suspend operator fun invoke(manga: List<Manga>): List<Manga> {
|
||||
return mangaRepository.insertNetworkManga(manga)
|
||||
}
|
||||
|
||||
// KMK -->
|
||||
suspend fun getLocal(manga: Manga): Manga = if (manga.id <= 0) {
|
||||
invoke(manga)
|
||||
} else {
|
||||
manga
|
||||
}
|
||||
|
||||
suspend fun getLocal(mangas: List<Manga>): List<Manga> {
|
||||
return mangas.map { manga ->
|
||||
if (manga.id <= 0) {
|
||||
invoke(manga)
|
||||
} else {
|
||||
manga
|
||||
}
|
||||
}
|
||||
}
|
||||
// KMK <--
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue