Use immutable collections in more places

This commit is contained in:
arkon
2023-11-11 22:43:50 -05:00
parent dd998be1e7
commit 336221a972
35 changed files with 252 additions and 152 deletions
@@ -6,6 +6,11 @@ import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.domain.extension.interactor.GetExtensionLanguages
import eu.kanade.domain.source.interactor.ToggleLanguage
import eu.kanade.domain.source.service.SourcePreferences
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.persistentSetOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toImmutableSet
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
@@ -41,8 +46,8 @@ class ExtensionFilterScreenModel(
.collectLatest { (extensionLanguages, enabledLanguages) ->
mutableState.update {
ExtensionFilterState.Success(
languages = extensionLanguages,
enabledLanguages = enabledLanguages,
languages = extensionLanguages.toImmutableList(),
enabledLanguages = enabledLanguages.toImmutableSet(),
)
}
}
@@ -65,8 +70,8 @@ sealed interface ExtensionFilterState {
@Immutable
data class Success(
val languages: List<String>,
val enabledLanguages: Set<String> = emptySet(),
val languages: ImmutableList<String>,
val enabledLanguages: ImmutableSet<String> = persistentSetOf(),
) : ExtensionFilterState {
val isEmpty: Boolean
@@ -12,6 +12,9 @@ import eu.kanade.tachiyomi.extension.model.Extension
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.system.LocaleHelper
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
@@ -75,10 +78,10 @@ class ExtensionDetailsScreenModel(
}
.catch { throwable ->
logcat(LogPriority.ERROR, throwable)
mutableState.update { it.copy(_sources = emptyList()) }
mutableState.update { it.copy(_sources = persistentListOf()) }
}
.collectLatest { sources ->
mutableState.update { it.copy(_sources = sources) }
mutableState.update { it.copy(_sources = sources.toImmutableList()) }
}
}
}
@@ -164,11 +167,11 @@ class ExtensionDetailsScreenModel(
@Immutable
data class State(
val extension: Extension.Installed? = null,
private val _sources: List<ExtensionSourceItem>? = null,
private val _sources: ImmutableList<ExtensionSourceItem>? = null,
) {
val sources: List<ExtensionSourceItem>
get() = _sources.orEmpty()
val sources: ImmutableList<ExtensionSourceItem>
get() = _sources ?: persistentListOf()
val isLoading: Boolean
get() = extension == null || _sources == null
@@ -4,6 +4,9 @@ import androidx.compose.runtime.Immutable
import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.tachiyomi.source.Source
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
@@ -40,11 +43,13 @@ class MigrateMangaScreenModel(
logcat(LogPriority.ERROR, it)
_events.send(MigrationMangaEvent.FailedFetchingFavorites)
mutableState.update { state ->
state.copy(titleList = emptyList())
state.copy(titleList = persistentListOf())
}
}
.map { manga ->
manga.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
manga
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
.toImmutableList()
}
.collectLatest { list ->
mutableState.update { it.copy(titleList = list) }
@@ -55,11 +60,11 @@ class MigrateMangaScreenModel(
@Immutable
data class State(
val source: Source? = null,
private val titleList: List<Manga>? = null,
private val titleList: ImmutableList<Manga>? = null,
) {
val titles: List<Manga>
get() = titleList.orEmpty()
val titles: ImmutableList<Manga>
get() = titleList ?: persistentListOf()
val isLoading: Boolean
get() = source == null || titleList == null
@@ -6,6 +6,9 @@ import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
import eu.kanade.domain.source.interactor.SetMigrateSorting
import eu.kanade.domain.source.service.SourcePreferences
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
@@ -40,7 +43,7 @@ class MigrateSourceScreenModel(
mutableState.update {
it.copy(
isLoading = false,
items = sources,
items = sources.toImmutableList(),
)
}
}
@@ -80,7 +83,7 @@ class MigrateSourceScreenModel(
@Immutable
data class State(
val isLoading: Boolean = true,
val items: List<Pair<Source, Long>> = emptyList(),
val items: ImmutableList<Pair<Source, Long>> = persistentListOf(),
val sortingMode: SetMigrateSorting.Mode = SetMigrateSorting.Mode.ALPHABETICAL,
val sortingDirection: SetMigrateSorting.Direction = SetMigrateSorting.Direction.ASCENDING,
) {
@@ -7,6 +7,9 @@ import eu.kanade.domain.source.interactor.GetEnabledSources
import eu.kanade.domain.source.interactor.ToggleSource
import eu.kanade.domain.source.interactor.ToggleSourcePin
import eu.kanade.presentation.browse.SourceUiModel
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
@@ -65,14 +68,16 @@ class SourcesScreenModel(
state.copy(
isLoading = false,
items = byLang.flatMap {
listOf(
SourceUiModel.Header(it.key),
*it.value.map { source ->
SourceUiModel.Item(source)
}.toTypedArray(),
)
},
items = byLang
.flatMap {
listOf(
SourceUiModel.Header(it.key),
*it.value.map { source ->
SourceUiModel.Item(source)
}.toTypedArray(),
)
}
.toImmutableList(),
)
}
}
@@ -103,7 +108,7 @@ class SourcesScreenModel(
data class State(
val dialog: Dialog? = null,
val isLoading: Boolean = true,
val items: List<SourceUiModel> = emptyList(),
val items: ImmutableList<SourceUiModel> = persistentListOf(),
) {
val isEmpty = items.isEmpty()
}
@@ -9,6 +9,10 @@ import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.presentation.util.ioCoroutineScope
import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.source.CatalogueSource
import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.mutate
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toPersistentMap
import kotlinx.coroutines.Job
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.async
@@ -125,9 +129,17 @@ abstract class SearchScreenModel(
// Reuse previous results if possible
if (sameQuery) {
val existingResults = state.value.items
updateItems(sources.associateWith { existingResults[it] ?: SearchItemResult.Loading })
updateItems(
sources
.associateWith { existingResults[it] ?: SearchItemResult.Loading }
.toPersistentMap(),
)
} else {
updateItems(sources.associateWith { SearchItemResult.Loading })
updateItems(
sources
.associateWith { SearchItemResult.Loading }
.toPersistentMap(),
)
}
searchJob = ioCoroutineScope.launch {
@@ -160,14 +172,21 @@ abstract class SearchScreenModel(
}
}
private fun updateItems(items: Map<CatalogueSource, SearchItemResult>) {
mutableState.update { it.copy(items = items.toSortedMap(sortComparator(items))) }
private fun updateItems(items: PersistentMap<CatalogueSource, SearchItemResult>) {
mutableState.update {
it.copy(
items = items
.toSortedMap(sortComparator(items))
.toPersistentMap(),
)
}
}
private fun updateItem(source: CatalogueSource, result: SearchItemResult) {
val mutableItems = state.value.items.toMutableMap()
mutableItems[source] = result
updateItems(mutableItems)
val newItems = state.value.items.mutate {
it[source] = result
}
updateItems(newItems)
}
@Immutable
@@ -176,7 +195,7 @@ abstract class SearchScreenModel(
val searchQuery: String? = null,
val sourceFilter: SourceFilter = SourceFilter.PinnedOnly,
val onlyShowHasResults: Boolean = false,
val items: Map<CatalogueSource, SearchItemResult> = emptyMap(),
val items: PersistentMap<CatalogueSource, SearchItemResult> = persistentMapOf(),
) {
val progress: Int = items.count { it.value !is SearchItemResult.Loading }
val total: Int = items.size