Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-29 17:58:31 +04:00
parent 36ce94fb22
commit 4342f888bd

View file

@ -1,37 +1,150 @@
package com.tangem.feature.tester.presentation.excludedblockchains
import androidx.lifecycle.ViewModel
import com.tangem.core.toggle.blockchain.MutableExcludedBlockchainsManager
import androidx.lifecycle.viewModelScope
import com.tangem.blockchain.common.Blockchain
import com.tangem.core.configtoggle.blockchain.MutableExcludedBlockchainsManager
import com.tangem.core.navigation.finisher.AppFinisher
import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.feature.tester.impl.R
import com.tangem.feature.tester.presentation.excludedblockchains.state.BlockchainUM
import com.tangem.feature.tester.presentation.excludedblockchains.state.ExcludedBlockchainsScreenUM
import com.tangem.feature.tester.presentation.excludedblockchains.state.mapper.toUiModels
import com.tangem.feature.tester.presentation.navigation.InnerTesterRouter
import com.tangem.utils.version.AppVersionProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.mutate
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
internal class ExcludedBlockchainsViewModel @Inject constructor(
private val excludedBlockchainsManager: MutableExcludedBlockchainsManager,
private val appVersionProvider: AppVersionProvider,
excludedBlockchainsManager: MutableExcludedBlockchainsManager?,
) : ViewModel() {
val uiState: MutableStateFlow<ExcludedBlockchainsScreenUM> = MutableStateFlow(
value = ExcludedBlockchainsScreenUM(
popBack = {},
search = SearchBarUM(
placeholderText = stringReference(value = "Filter by name or symbol"),
query = "",
isActive = false,
onQueryChange = {},
onActiveChange = {},
),
blockchains = persistentListOf(),
onRestartClick = {},
onRestoreClick = {},
),
private val excludedBlockchainsManager: MutableExcludedBlockchainsManager =
requireNotNull(excludedBlockchainsManager) {
"Mutable excluded blockchains manager can't be null when tester actions is available"
}
val state: MutableStateFlow<ExcludedBlockchainsScreenUM> = MutableStateFlow(
value = getInitialState(),
)
fun setupNavigation(router: InnerTesterRouter) {
init {
observeQueryUpdates()
}
fun setupNavigation(router: InnerTesterRouter, appFinisher: AppFinisher) {
state.update { state ->
state.copy(
popBack = router::back,
onRestartClick = appFinisher::finish,
)
}
}
private fun getInitialState(): ExcludedBlockchainsScreenUM = ExcludedBlockchainsScreenUM(
popBack = {},
search = getInitialSearchBar(),
blockchains = getBlockchains(),
showRecoverWarning = !excludedBlockchainsManager.isMatchLocalConfig(),
appVersion = appVersionProvider.versionName,
onRestartClick = {},
onRecoverClick = ::recoverLocalConfig,
)
@OptIn(FlowPreview::class)
private fun observeQueryUpdates() {
state
.map { it.search.query }
.distinctUntilChanged()
.drop(count = 1) // Skip initial value
.sample(periodMillis = 1_000)
.onEach(::filterBlockchains)
.launchIn(viewModelScope)
}
private fun recoverLocalConfig() = viewModelScope.launch {
excludedBlockchainsManager.recoverLocalConfig()
state.update { state ->
state.copy(
search = getInitialSearchBar(),
blockchains = getBlockchains(),
)
}
}
private fun getBlockchains(): PersistentList<BlockchainUM> {
val excludedBlockchains = excludedBlockchainsManager.excludedBlockchainsIds
return Blockchain.entries.toUiModels(
excludedBlockchainsIds = excludedBlockchains,
onExcludedStateChange = ::excludeBlockchain,
).toPersistentList()
}
private fun getInitialSearchBar(): SearchBarUM = SearchBarUM(
placeholderText = resourceReference(R.string.excluded_blockchains_search_placeholder),
query = "",
isActive = false,
onQueryChange = ::updateQuery,
onActiveChange = ::updateSearchBarState,
)
private fun excludeBlockchain(blockchain: Blockchain, isExcluded: Boolean) = viewModelScope.launch {
excludedBlockchainsManager.excludeBlockchain(blockchain.id, isExcluded)
state.update { state ->
state.copy(
blockchains = state.blockchains.mutate { mutableBlockchains ->
val index = mutableBlockchains.indexOfFirst { it.id == blockchain.id }
if (index == -1) return@mutate
mutableBlockchains[index] = mutableBlockchains[index].copy(isExcluded = isExcluded)
},
showRecoverWarning = !excludedBlockchainsManager.isMatchLocalConfig(),
)
}
}
private fun filterBlockchains(query: String) {
val filteredBlockchains = if (query.isBlank()) {
getBlockchains()
} else {
getBlockchains().filter { blockchain ->
blockchain.name.contains(query, ignoreCase = true) ||
blockchain.symbol.contains(query, ignoreCase = true)
}.toPersistentList()
}
state.update { state ->
state.copy(
blockchains = filteredBlockchains,
)
}
}
private fun updateQuery(query: String) {
state.update { state ->
state.copy(
search = state.search.copy(query = query),
)
}
}
private fun updateSearchBarState(isActive: Boolean) {
state.update { state ->
state.copy(
search = state.search.copy(isActive = isActive),
)
}
}
}