diff --git a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt index 7e4697e68..4df4179fe 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt @@ -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, diff --git a/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt index 3b41222ff..31abb596c 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt @@ -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, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt index 0d30b5180..bf41dc276 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt @@ -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) : 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 = { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenDialogScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenDialogScreenModel.kt new file mode 100644 index 000000000..6053e5780 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenDialogScreenModel.kt @@ -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(State()) { + + init { + coroutineScope.launch { + val manga = getManga.await(mangaId)!! + + mutableState.update { + it.copy(manga = manga) + } + } + } + + @Immutable + data class State( + val manga: Manga? = null, + ) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt index db4cea7ed..1fdc5bb54 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt @@ -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, // SY <-- - private val sourcePreferences: SourcePreferences = Injekt.get(), - private val sourceManager: SourceManager = Injekt.get(), - private val getManga: GetManga = Injekt.get(), -) : SearchScreenModel(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) { - mutableState.update { - it.copy(items = items) - } - } - - override fun getItems(): Map { - 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 = emptyMap(), - ) { - val progress: Int = items.count { it.value !is SearchItemResult.Loading } - val total: Int = items.size - val filteredItems = items.filter { (_, result) -> result.isVisible(onlyShowHasResults) } - } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt index fe30da8f0..844755766 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt @@ -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(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) { - mutableState.update { - it.copy(items = items) - } - } - - override fun getItems(): Map { - 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 = emptyMap(), - ) { - val progress: Int = items.count { it.value !is SearchItemResult.Loading } - val total: Int = items.size - val filteredItems = items.filter { (_, result) -> result.isVisible(onlyShowHasResults) } - } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt index f0e4710b1..95dbb72ad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt @@ -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( - 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(initialState) { + protected val getManga: GetManga = Injekt.get(), +) : StateScreenModel(initialState) { private val coroutineDispatcher = Executors.newFixedThreadPool(5).asCoroutineDispatcher() private var searchJob: Job? = null @@ -55,7 +54,7 @@ abstract class SearchScreenModel( } @Composable - fun getManga(initialManga: Manga): State { + fun getManga(initialManga: Manga): androidx.compose.runtime.State { return produceState(initialValue = initialManga) { getManga.subscribe(initialManga.url, initialManga.source) .filterNotNull() @@ -98,19 +97,25 @@ abstract class SearchScreenModel( // SY <-- } - abstract fun updateSearchQuery(query: String?) - - abstract fun updateItems(items: Map) - - abstract fun getItems(): Map - - private fun getAndUpdateItems(function: (Map) -> Map) { - updateItems(function(getItems())) + fun updateSearchQuery(query: String?) { + mutableState.update { + it.copy(searchQuery = query) + } } - abstract fun setSourceFilter(filter: SourceFilter) + fun getItems(): Map { + 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( .awaitAll() } } + + private fun updateItems(items: Map) { + mutableState.update { + it.copy(items = items) + } + } + + private fun getAndUpdateItems(function: (Map) -> Map) { + 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 = 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 {