Dedupe SearchScreenModels

(cherry picked from commit ca789dca0ee5d24f9fc363be8daaf170f04054a9)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt
This commit is contained in:
arkon 2023-07-16 19:44:32 -04:00 committed by Jobobby04
parent 2a5c869b1a
commit 7b763712f5
7 changed files with 94 additions and 121 deletions

View File

@ -10,8 +10,8 @@ import eu.kanade.presentation.browse.components.GlobalSearchLoadingResultItem
import eu.kanade.presentation.browse.components.GlobalSearchResultItem
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
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.SearchScreenModel
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
import eu.kanade.tachiyomi.util.system.LocaleHelper
import tachiyomi.domain.manga.model.Manga
@ -19,7 +19,7 @@ import tachiyomi.presentation.core.components.material.Scaffold
@Composable
fun GlobalSearchScreen(
state: GlobalSearchScreenModel.State,
state: SearchScreenModel.State,
navigateUp: () -> Unit,
onChangeSearchQuery: (String?) -> Unit,
onSearch: (String) -> Unit,

View File

@ -4,14 +4,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
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 tachiyomi.domain.manga.model.Manga
import tachiyomi.presentation.core.components.material.Scaffold
@Composable
fun MigrateSearchScreen(
state: MigrateSearchScreenModel.State,
state: SearchScreenModel.State,
fromSourceId: Long?,
navigateUp: () -> Unit,
onChangeSearchQuery: (String?) -> Unit,
onSearch: (String) -> Unit,
@ -40,7 +41,7 @@ fun MigrateSearchScreen(
},
) { paddingValues ->
GlobalSearchContent(
fromSourceId = state.manga?.source,
fromSourceId = fromSourceId,
items = state.filteredItems,
contentPadding = paddingValues,
getManga = getManga,

View File

@ -11,7 +11,6 @@ import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListScreen
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, private val validSources: List<Long>) : Screen() {
@Composable
@ -20,8 +19,12 @@ class MigrateSearchScreen(private val mangaId: Long, private val validSources: L
val screenModel = rememberScreenModel { MigrateSearchScreenModel(mangaId = mangaId, validSources = validSources) }
val state by screenModel.state.collectAsState()
val dialogScreenModel = rememberScreenModel { MigrateSearchScreenDialogScreenModel(mangaId = mangaId) }
val dialogState by dialogScreenModel.state.collectAsState()
MigrateSearchScreen(
state = state,
fromSourceId = state.fromSourceId,
navigateUp = navigator::pop,
onChangeSearchQuery = screenModel::updateSearchQuery,
onSearch = screenModel::search,
@ -30,7 +33,7 @@ class MigrateSearchScreen(private val mangaId: Long, private val validSources: L
onToggleResults = screenModel::toggleFilterResults,
onClickSource = {
// SY -->
navigator.push(SourceSearchScreen(state.manga!!, it.id, state.searchQuery))
navigator.push(SourceSearchScreen(dialogState.manga!!, it.id, state.searchQuery))
// SY <--
},
onClickItem = {

View File

@ -0,0 +1,32 @@
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)
}
}
}
@Immutable
data class State(
val manga: Manga? = null,
)
}

View File

@ -1,36 +1,25 @@
package eu.kanade.tachiyomi.ui.browse.migration.search
import androidx.compose.runtime.Immutable
import cafe.adriel.voyager.core.model.coroutineScope
import eu.kanade.domain.source.service.SourcePreferences
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.SourceFilter
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import tachiyomi.domain.manga.interactor.GetManga
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.service.SourceManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class MigrateSearchScreenModel(
val mangaId: Long,
// SY -->
val validSources: List<Long>,
// SY <--
private val sourcePreferences: SourcePreferences = Injekt.get(),
private val sourceManager: SourceManager = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
) : SearchScreenModel<MigrateSearchScreenModel.State>(State()) {
) : SearchScreenModel() {
init {
coroutineScope.launch {
val manga = getManga.await(mangaId)!!
mutableState.update {
it.copy(manga = manga, searchQuery = manga.title)
it.copy(fromSourceId = manga.source, searchQuery = manga.title)
}
search(manga.title)
@ -45,44 +34,4 @@ class MigrateSearchScreenModel(
.filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources }
// SY <--
}
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 manga: Manga? = 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) }
}
}

View File

@ -1,13 +1,11 @@
package eu.kanade.tachiyomi.ui.browse.source.globalsearch
import androidx.compose.runtime.Immutable
import eu.kanade.tachiyomi.source.CatalogueSource
import kotlinx.coroutines.flow.update
class GlobalSearchScreenModel(
initialQuery: String = "",
initialExtensionFilter: String? = null,
) : SearchScreenModel<GlobalSearchScreenModel.State>(State(searchQuery = initialQuery)) {
) : SearchScreenModel(State(searchQuery = initialQuery)) {
init {
extensionFilter = initialExtensionFilter
@ -20,42 +18,4 @@ class GlobalSearchScreenModel(
return super.getEnabledSources()
.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) }
}
}

View File

@ -1,10 +1,9 @@
package eu.kanade.tachiyomi.ui.browse.source.globalsearch
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.produceState
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.source.service.SourcePreferences
import eu.kanade.presentation.util.ioCoroutineScope
@ -16,6 +15,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import tachiyomi.core.util.lang.awaitSingle
@ -27,15 +27,14 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.concurrent.Executors
abstract class SearchScreenModel<T>(
initialState: T,
private val sourcePreferences: SourcePreferences = Injekt.get(),
private val sourceManager: SourceManager = Injekt.get(),
abstract class SearchScreenModel(
initialState: State = State(),
protected val sourcePreferences: SourcePreferences = Injekt.get(),
protected val sourceManager: SourceManager = Injekt.get(),
private val extensionManager: ExtensionManager = Injekt.get(),
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
private val updateManga: UpdateManga = Injekt.get(),
) : StateScreenModel<T>(initialState) {
protected val getManga: GetManga = Injekt.get(),
) : StateScreenModel<SearchScreenModel.State>(initialState) {
private val coroutineDispatcher = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
private var searchJob: Job? = null
@ -55,7 +54,7 @@ abstract class SearchScreenModel<T>(
}
@Composable
fun getManga(initialManga: Manga): State<Manga> {
fun getManga(initialManga: Manga): androidx.compose.runtime.State<Manga> {
return produceState(initialValue = initialManga) {
getManga.subscribe(initialManga.url, initialManga.source)
.filterNotNull()
@ -98,19 +97,25 @@ abstract class SearchScreenModel<T>(
// SY <--
}
abstract fun updateSearchQuery(query: String?)
abstract fun updateItems(items: Map<CatalogueSource, SearchItemResult>)
abstract fun getItems(): Map<CatalogueSource, SearchItemResult>
private fun getAndUpdateItems(function: (Map<CatalogueSource, SearchItemResult>) -> Map<CatalogueSource, SearchItemResult>) {
updateItems(function(getItems()))
fun updateSearchQuery(query: String?) {
mutableState.update {
it.copy(searchQuery = query)
}
}
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) {
if (this.query == query) return
@ -150,6 +155,29 @@ abstract class SearchScreenModel<T>(
.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 {