Dedupe SearchScreenModels
This commit is contained in:
parent
ef7b285151
commit
ca789dca0e
7 changed files with 108 additions and 127 deletions
|
@ -10,8 +10,8 @@ import eu.kanade.presentation.browse.components.GlobalSearchLoadingResultItem
|
||||||
import eu.kanade.presentation.browse.components.GlobalSearchResultItem
|
import eu.kanade.presentation.browse.components.GlobalSearchResultItem
|
||||||
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
|
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreenModel
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
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 eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
@ -19,7 +19,7 @@ import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GlobalSearchScreen(
|
fun GlobalSearchScreen(
|
||||||
state: GlobalSearchScreenModel.State,
|
state: SearchScreenModel.State,
|
||||||
navigateUp: () -> Unit,
|
navigateUp: () -> Unit,
|
||||||
onChangeSearchQuery: (String?) -> Unit,
|
onChangeSearchQuery: (String?) -> Unit,
|
||||||
onSearch: (String) -> Unit,
|
onSearch: (String) -> Unit,
|
||||||
|
|
|
@ -4,14 +4,15 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
|
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateSearchScreenModel
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchScreenModel
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
|
||||||
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
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MigrateSearchScreen(
|
fun MigrateSearchScreen(
|
||||||
state: MigrateSearchScreenModel.State,
|
state: SearchScreenModel.State,
|
||||||
|
fromSourceId: Long?,
|
||||||
navigateUp: () -> Unit,
|
navigateUp: () -> Unit,
|
||||||
onChangeSearchQuery: (String?) -> Unit,
|
onChangeSearchQuery: (String?) -> Unit,
|
||||||
onSearch: (String) -> Unit,
|
onSearch: (String) -> Unit,
|
||||||
|
@ -40,7 +41,7 @@ fun MigrateSearchScreen(
|
||||||
},
|
},
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
GlobalSearchContent(
|
GlobalSearchContent(
|
||||||
fromSourceId = state.manga?.source,
|
fromSourceId = fromSourceId,
|
||||||
items = state.filteredItems,
|
items = state.filteredItems,
|
||||||
contentPadding = paddingValues,
|
contentPadding = paddingValues,
|
||||||
getManga = getManga,
|
getManga = getManga,
|
||||||
|
|
|
@ -10,7 +10,6 @@ import eu.kanade.presentation.browse.MigrateSearchScreen
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||||
|
|
||||||
// TODO: this should probably be merged with GlobalSearchScreen somehow to dedupe logic
|
|
||||||
class MigrateSearchScreen(private val mangaId: Long) : Screen() {
|
class MigrateSearchScreen(private val mangaId: Long) : Screen() {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -20,8 +19,12 @@ class MigrateSearchScreen(private val mangaId: Long) : Screen() {
|
||||||
val screenModel = rememberScreenModel { MigrateSearchScreenModel(mangaId = mangaId) }
|
val screenModel = rememberScreenModel { MigrateSearchScreenModel(mangaId = mangaId) }
|
||||||
val state by screenModel.state.collectAsState()
|
val state by screenModel.state.collectAsState()
|
||||||
|
|
||||||
|
val dialogScreenModel = rememberScreenModel { MigrateSearchScreenDialogScreenModel(mangaId = mangaId) }
|
||||||
|
val dialogState by dialogScreenModel.state.collectAsState()
|
||||||
|
|
||||||
MigrateSearchScreen(
|
MigrateSearchScreen(
|
||||||
state = state,
|
state = state,
|
||||||
|
fromSourceId = dialogState.manga?.source,
|
||||||
navigateUp = navigator::pop,
|
navigateUp = navigator::pop,
|
||||||
onChangeSearchQuery = screenModel::updateSearchQuery,
|
onChangeSearchQuery = screenModel::updateSearchQuery,
|
||||||
onSearch = screenModel::search,
|
onSearch = screenModel::search,
|
||||||
|
@ -29,19 +32,19 @@ class MigrateSearchScreen(private val mangaId: Long) : Screen() {
|
||||||
onChangeSearchFilter = screenModel::setSourceFilter,
|
onChangeSearchFilter = screenModel::setSourceFilter,
|
||||||
onToggleResults = screenModel::toggleFilterResults,
|
onToggleResults = screenModel::toggleFilterResults,
|
||||||
onClickSource = {
|
onClickSource = {
|
||||||
navigator.push(SourceSearchScreen(state.manga!!, it.id, state.searchQuery))
|
navigator.push(SourceSearchScreen(dialogState.manga!!, it.id, state.searchQuery))
|
||||||
},
|
},
|
||||||
onClickItem = { screenModel.setDialog(MigrateSearchScreenModel.Dialog.Migrate(it)) },
|
onClickItem = { dialogScreenModel.setDialog(MigrateSearchScreenDialogScreenModel.Dialog.Migrate(it)) },
|
||||||
onLongClickItem = { navigator.push(MangaScreen(it.id, true)) },
|
onLongClickItem = { navigator.push(MangaScreen(it.id, true)) },
|
||||||
)
|
)
|
||||||
|
|
||||||
when (val dialog = state.dialog) {
|
when (val dialog = dialogState.dialog) {
|
||||||
is MigrateSearchScreenModel.Dialog.Migrate -> {
|
is MigrateSearchScreenDialogScreenModel.Dialog.Migrate -> {
|
||||||
MigrateDialog(
|
MigrateDialog(
|
||||||
oldManga = state.manga!!,
|
oldManga = dialogState.manga!!,
|
||||||
newManga = dialog.manga,
|
newManga = dialog.manga,
|
||||||
screenModel = rememberScreenModel { MigrateDialogScreenModel() },
|
screenModel = rememberScreenModel { MigrateDialogScreenModel() },
|
||||||
onDismissRequest = { screenModel.setDialog(null) },
|
onDismissRequest = { dialogScreenModel.setDialog(null) },
|
||||||
onClickTitle = {
|
onClickTitle = {
|
||||||
navigator.push(MangaScreen(dialog.manga.id, true))
|
navigator.push(MangaScreen(dialog.manga.id, true))
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package eu.kanade.tachiyomi.ui.browse.migration.search
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
|
import cafe.adriel.voyager.core.model.coroutineScope
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import tachiyomi.domain.manga.interactor.GetManga
|
||||||
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class MigrateSearchScreenDialogScreenModel(
|
||||||
|
val mangaId: Long,
|
||||||
|
getManga: GetManga = Injekt.get(),
|
||||||
|
) : StateScreenModel<MigrateSearchScreenDialogScreenModel.State>(State()) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
coroutineScope.launch {
|
||||||
|
val manga = getManga.await(mangaId)!!
|
||||||
|
|
||||||
|
mutableState.update {
|
||||||
|
it.copy(manga = manga)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setDialog(dialog: Dialog?) {
|
||||||
|
mutableState.update {
|
||||||
|
it.copy(dialog = dialog)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class State(
|
||||||
|
val manga: Manga? = null,
|
||||||
|
val dialog: Dialog? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
sealed class Dialog {
|
||||||
|
data class Migrate(val manga: Manga) : Dialog()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,29 +1,26 @@
|
||||||
package eu.kanade.tachiyomi.ui.browse.migration.search
|
package eu.kanade.tachiyomi.ui.browse.migration.search
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import cafe.adriel.voyager.core.model.coroutineScope
|
import cafe.adriel.voyager.core.model.coroutineScope
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
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.SearchScreenModel
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import tachiyomi.domain.manga.interactor.GetManga
|
import tachiyomi.domain.manga.interactor.GetManga
|
||||||
import tachiyomi.domain.manga.model.Manga
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class MigrateSearchScreenModel(
|
class MigrateSearchScreenModel(
|
||||||
val mangaId: Long,
|
val mangaId: Long,
|
||||||
getManga: GetManga = Injekt.get(),
|
getManga: GetManga = Injekt.get(),
|
||||||
) : SearchScreenModel<MigrateSearchScreenModel.State>(State()) {
|
) : SearchScreenModel() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
val manga = getManga.await(mangaId)!!
|
val manga = getManga.await(mangaId)!!
|
||||||
|
|
||||||
mutableState.update {
|
mutableState.update {
|
||||||
it.copy(manga = manga, searchQuery = manga.title)
|
it.copy(fromSourceId = manga.source, searchQuery = manga.title)
|
||||||
}
|
}
|
||||||
|
|
||||||
search(manga.title)
|
search(manga.title)
|
||||||
|
@ -35,61 +32,10 @@ class MigrateSearchScreenModel(
|
||||||
.filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources }
|
.filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources }
|
||||||
.sortedWith(
|
.sortedWith(
|
||||||
compareBy(
|
compareBy(
|
||||||
{ it.id != state.value.manga!!.source },
|
{ it.id != state.value.fromSourceId },
|
||||||
{ "${it.id}" !in pinnedSources },
|
{ "${it.id}" !in pinnedSources },
|
||||||
{ "${it.name.lowercase()} (${it.lang})" },
|
{ "${it.name.lowercase()} (${it.lang})" },
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateSearchQuery(query: String?) {
|
|
||||||
mutableState.update {
|
|
||||||
it.copy(searchQuery = query)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateItems(items: Map<CatalogueSource, SearchItemResult>) {
|
|
||||||
mutableState.update {
|
|
||||||
it.copy(items = items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItems(): Map<CatalogueSource, SearchItemResult> {
|
|
||||||
return mutableState.value.items
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setSourceFilter(filter: SourceFilter) {
|
|
||||||
mutableState.update { it.copy(sourceFilter = filter) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toggleFilterResults() {
|
|
||||||
mutableState.update {
|
|
||||||
it.copy(onlyShowHasResults = !it.onlyShowHasResults)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setDialog(dialog: Dialog?) {
|
|
||||||
mutableState.update {
|
|
||||||
it.copy(dialog = dialog)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
data class State(
|
|
||||||
val manga: Manga? = null,
|
|
||||||
val dialog: Dialog? = null,
|
|
||||||
|
|
||||||
val searchQuery: String? = null,
|
|
||||||
val sourceFilter: SourceFilter = SourceFilter.PinnedOnly,
|
|
||||||
val onlyShowHasResults: Boolean = false,
|
|
||||||
val items: Map<CatalogueSource, SearchItemResult> = emptyMap(),
|
|
||||||
) {
|
|
||||||
val progress: Int = items.count { it.value !is SearchItemResult.Loading }
|
|
||||||
val total: Int = items.size
|
|
||||||
val filteredItems = items.filter { (_, result) -> result.isVisible(onlyShowHasResults) }
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Dialog {
|
|
||||||
data class Migrate(val manga: Manga) : Dialog()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package eu.kanade.tachiyomi.ui.browse.source.globalsearch
|
package eu.kanade.tachiyomi.ui.browse.source.globalsearch
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import kotlinx.coroutines.flow.update
|
|
||||||
|
|
||||||
class GlobalSearchScreenModel(
|
class GlobalSearchScreenModel(
|
||||||
initialQuery: String = "",
|
initialQuery: String = "",
|
||||||
initialExtensionFilter: String? = null,
|
initialExtensionFilter: String? = null,
|
||||||
) : SearchScreenModel<GlobalSearchScreenModel.State>(State(searchQuery = initialQuery)) {
|
) : SearchScreenModel(State(searchQuery = initialQuery)) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
extensionFilter = initialExtensionFilter
|
extensionFilter = initialExtensionFilter
|
||||||
|
@ -20,42 +18,4 @@ class GlobalSearchScreenModel(
|
||||||
return super.getEnabledSources()
|
return super.getEnabledSources()
|
||||||
.filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources }
|
.filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateSearchQuery(query: String?) {
|
|
||||||
mutableState.update {
|
|
||||||
it.copy(searchQuery = query)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateItems(items: Map<CatalogueSource, SearchItemResult>) {
|
|
||||||
mutableState.update {
|
|
||||||
it.copy(items = items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItems(): Map<CatalogueSource, SearchItemResult> {
|
|
||||||
return mutableState.value.items
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setSourceFilter(filter: SourceFilter) {
|
|
||||||
mutableState.update { it.copy(sourceFilter = filter) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toggleFilterResults() {
|
|
||||||
mutableState.update {
|
|
||||||
it.copy(onlyShowHasResults = !it.onlyShowHasResults)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
data class State(
|
|
||||||
val searchQuery: String? = null,
|
|
||||||
val sourceFilter: SourceFilter = SourceFilter.PinnedOnly,
|
|
||||||
val onlyShowHasResults: Boolean = false,
|
|
||||||
val items: Map<CatalogueSource, SearchItemResult> = emptyMap(),
|
|
||||||
) {
|
|
||||||
val progress: Int = items.count { it.value !is SearchItemResult.Loading }
|
|
||||||
val total: Int = items.size
|
|
||||||
val filteredItems = items.filter { (_, result) -> result.isVisible(onlyShowHasResults) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package eu.kanade.tachiyomi.ui.browse.source.globalsearch
|
package eu.kanade.tachiyomi.ui.browse.source.globalsearch
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.runtime.produceState
|
import androidx.compose.runtime.produceState
|
||||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
|
||||||
import eu.kanade.domain.manga.model.toDomainManga
|
import eu.kanade.domain.manga.model.toDomainManga
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.presentation.util.ioCoroutineScope
|
import eu.kanade.presentation.util.ioCoroutineScope
|
||||||
|
@ -16,6 +15,7 @@ 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.filterNotNull
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import tachiyomi.core.util.lang.awaitSingle
|
import tachiyomi.core.util.lang.awaitSingle
|
||||||
|
@ -27,15 +27,14 @@ import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
abstract class SearchScreenModel<T>(
|
abstract class SearchScreenModel(
|
||||||
initialState: T,
|
initialState: State = State(),
|
||||||
private val sourcePreferences: SourcePreferences = Injekt.get(),
|
private val 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(),
|
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga = Injekt.get(),
|
||||||
private val updateManga: UpdateManga = Injekt.get(),
|
) : StateScreenModel<SearchScreenModel.State>(initialState) {
|
||||||
) : StateScreenModel<T>(initialState) {
|
|
||||||
|
|
||||||
private val coroutineDispatcher = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
|
private val coroutineDispatcher = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
|
||||||
private var searchJob: Job? = null
|
private var searchJob: Job? = null
|
||||||
|
@ -55,7 +54,7 @@ abstract class SearchScreenModel<T>(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun getManga(initialManga: Manga): 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()
|
.filterNotNull()
|
||||||
|
@ -95,19 +94,25 @@ abstract class SearchScreenModel<T>(
|
||||||
.filter { it in enabledSources }
|
.filter { it in enabledSources }
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun updateSearchQuery(query: String?)
|
fun updateSearchQuery(query: String?) {
|
||||||
|
mutableState.update {
|
||||||
abstract fun updateItems(items: Map<CatalogueSource, SearchItemResult>)
|
it.copy(searchQuery = query)
|
||||||
|
}
|
||||||
abstract fun getItems(): Map<CatalogueSource, SearchItemResult>
|
|
||||||
|
|
||||||
private fun getAndUpdateItems(function: (Map<CatalogueSource, SearchItemResult>) -> Map<CatalogueSource, SearchItemResult>) {
|
|
||||||
updateItems(function(getItems()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun setSourceFilter(filter: SourceFilter)
|
fun getItems(): Map<CatalogueSource, SearchItemResult> {
|
||||||
|
return mutableState.value.items
|
||||||
|
}
|
||||||
|
|
||||||
abstract fun toggleFilterResults()
|
fun setSourceFilter(filter: SourceFilter) {
|
||||||
|
mutableState.update { it.copy(sourceFilter = filter) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleFilterResults() {
|
||||||
|
mutableState.update {
|
||||||
|
it.copy(onlyShowHasResults = !it.onlyShowHasResults)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun search(query: String) {
|
fun search(query: String) {
|
||||||
if (this.query == query) return
|
if (this.query == query) return
|
||||||
|
@ -147,6 +152,29 @@ abstract class SearchScreenModel<T>(
|
||||||
.awaitAll()
|
.awaitAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateItems(items: Map<CatalogueSource, SearchItemResult>) {
|
||||||
|
mutableState.update {
|
||||||
|
it.copy(items = items)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAndUpdateItems(function: (Map<CatalogueSource, SearchItemResult>) -> Map<CatalogueSource, SearchItemResult>) {
|
||||||
|
updateItems(function(getItems()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class State(
|
||||||
|
val fromSourceId: Long? = null,
|
||||||
|
val searchQuery: String? = null,
|
||||||
|
val sourceFilter: SourceFilter = SourceFilter.PinnedOnly,
|
||||||
|
val onlyShowHasResults: Boolean = false,
|
||||||
|
val items: Map<CatalogueSource, SearchItemResult> = emptyMap(),
|
||||||
|
) {
|
||||||
|
val progress: Int = items.count { it.value !is SearchItemResult.Loading }
|
||||||
|
val total: Int = items.size
|
||||||
|
val filteredItems = items.filter { (_, result) -> result.isVisible(onlyShowHasResults) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class SourceFilter {
|
enum class SourceFilter {
|
||||||
|
|
Reference in a new issue