Skip to content

Commit

Permalink
Fast browsing (#612)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
cuong-tran authored Dec 31, 2024
1 parent 1f3d2cb commit 5fc9e20
Show file tree
Hide file tree
Showing 25 changed files with 336 additions and 199 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.paging.LoadState
Expand All @@ -24,7 +23,6 @@ import eu.kanade.presentation.browse.components.BrowseSourceList
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.util.formattedMessage
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
import exh.metadata.metadata.RaisedSearchMetadata
import exh.source.isEhBasedSource
import kotlinx.collections.immutable.persistentListOf
Expand Down Expand Up @@ -62,7 +60,6 @@ fun BrowseSourceContent(
onMangaLongClick: (Manga) -> Unit,
// KMK -->
selection: List<Manga>,
browseSourceState: BrowseSourceScreenModel.State,
// KMK <--
) {
val context = LocalContext.current
Expand Down Expand Up @@ -138,22 +135,9 @@ fun BrowseSourceContent(
LoadingScreen(
modifier = Modifier.padding(contentPadding),
)
// KMK -->
browseSourceState.mangaDisplayingList.clear()
// KMK <--
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 -->
if (source?.isEhBasedSource() == true && ehentaiBrowseDisplayMode) {
BrowseSourceEHentaiList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
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.Text
import androidx.compose.runtime.Composable
Expand Down Expand Up @@ -33,6 +31,7 @@ fun BulkSelectionToolbar(
actions = persistentListOf<AppBar.AppBarAction>()
.builder()
.apply {
/*
if (onSelectAll != null) {
add(
AppBar.Action(
Expand All @@ -51,6 +50,7 @@ fun BulkSelectionToolbar(
),
)
}
*/
if (isRunning) {
add(
AppBar.ActionCompose(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

data object BrowseTab : Tab {
private fun readResolve(): Any = BrowseTab

override val options: TabOptions
@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.hapticfeedback.HapticFeedback
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.util.fastAny
import androidx.compose.ui.util.fastDistinctBy
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastForEachIndexed
import cafe.adriel.voyager.core.model.StateScreenModel
Expand Down Expand Up @@ -113,7 +114,9 @@ class BulkFavoriteScreenModel(
mutableState.update { state ->
val newSelection = mangas.filterNot { manga ->
state.selection.contains(manga)
}.toPersistentList()
}
.fastDistinctBy { it.id }
.toPersistentList()
state.copy(
selection = newSelection,
selectionMode = newSelection.isNotEmpty(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
Expand Down Expand Up @@ -58,7 +59,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(),
Expand Down Expand Up @@ -318,9 +319,9 @@ open class FeedScreenModel(
val result = withIOContext {
itemUI.copy(
results = page.map {
networkToLocalManga.await(it.toDomainManga(itemUI.source!!.id))
}
// KMK -->
it.toDomainManga(itemUI.source!!.id)
}
.filter { !hideInLibraryFeedItems.get() || !it.favorite },
// KMK <--
)
Expand Down Expand Up @@ -355,8 +356,10 @@ open class FeedScreenModel(
return produceState(initialValue = initialManga) {
getManga.subscribe(initialManga.url, initialManga.source)
.collectLatest { manga ->
if (manga == null) return@collectLatest
value = manga
// KMK -->
?: initialManga
// KMK <--
}
}
}
Expand Down
31 changes: 20 additions & 11 deletions app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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.stack.StackEvent
Expand Down Expand Up @@ -40,6 +41,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
Expand All @@ -57,6 +59,7 @@ fun feedTab(
val state by screenModel.state.collectAsState()

// KMK -->
val scope = rememberCoroutineScope()
val bulkFavoriteState by bulkFavoriteScreenModel.state.collectAsState()
val showingFeedOrderScreen = rememberSaveable { mutableStateOf(false) }

Expand Down Expand Up @@ -175,21 +178,27 @@ fun 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -14,6 +15,7 @@ import eu.kanade.tachiyomi.ui.browse.BulkFavoriteScreenModel
import eu.kanade.tachiyomi.ui.browse.ChangeMangasCategoryDialog
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListScreen
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() {

Expand All @@ -28,6 +30,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()

Expand All @@ -52,21 +55,31 @@ class MigrateSearchScreen(private val mangaId: Long, private val validSources: L
},
onClickItem = {
// KMK -->
if (bulkFavoriteState.selectionMode) {
bulkFavoriteScreenModel.toggleSelection(it)
} else
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 <--
{
// SY -->
navigator.items
.filterIsInstance<MigrationListScreen>()
.last()
.newSelectedItem = mangaId to it.id
navigator.popUntil { it is MigrationListScreen }
// SY <--
}
navigator.push(MangaScreen(manga.id, true))
}
},
onLongClickItem = { navigator.push(MangaScreen(it.id, true)) },
// KMK -->
bulkFavoriteScreenModel = bulkFavoriteScreenModel,
hasPinnedSources = screenModel.hasPinnedSources(),
Expand Down
Loading

0 comments on commit 5fc9e20

Please sign in to comment.