diff --git a/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt index 71f04d42af..22932d20e9 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt @@ -1,22 +1,22 @@ package com.tangem.tap.common.redux.legacy +import com.tangem.domain.apptheme.model.AppThemeMode import com.tangem.domain.redux.LegacyAction import com.tangem.tap.common.extensions.dispatchWithMain import com.tangem.tap.common.extensions.inject import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction +import com.tangem.tap.features.details.redux.AppSettingsState import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStartedSource import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store +import com.tangem.tap.tangemSdkManager import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.* import org.rekotlin.Middleware internal object LegacyMiddleware { @@ -42,10 +42,13 @@ internal object LegacyMiddleware { userWalletsListManager.selectedUserWallet .distinctUntilChanged() .onEach { selectedUserWallet -> + val initializedAppSettingsStateContent = initializeAppSettingsState( + shouldSaveUserWallets = walletsRepository.shouldSaveUserWalletsSync(), + ) store.dispatchWithMain( DetailsAction.PrepareScreen( scanResponse = selectedUserWallet.scanResponse, - shouldSaveUserWallets = walletsRepository.shouldSaveUserWalletsSync(), + initializedAppSettingsState = initializedAppSettingsStateContent, ), ) } @@ -58,4 +61,22 @@ internal object LegacyMiddleware { } } } + + /** + * LEGACY: We need to initialize [AppSettingsState] async to avoid drawing blocking + * previously it was initialized in runBlocking and blocked details screen + */ + private suspend fun initializeAppSettingsState(shouldSaveUserWallets: Boolean): AppSettingsState { + return AppSettingsState( + isBiometricsAvailable = tangemSdkManager.checkCanUseBiometry(), + saveWallets = shouldSaveUserWallets, + saveAccessCodes = store.inject(DaggerGraphState::settingsRepository).shouldSaveAccessCodes(), + selectedAppCurrency = store.state.globalState.appCurrency, + selectedThemeMode = store.inject(DaggerGraphState::appThemeModeRepository).getAppThemeMode().firstOrNull() + ?: AppThemeMode.DEFAULT, + isHidingEnabled = store.inject(DaggerGraphState::balanceHidingRepository) + .getBalanceHidingSettings().isHidingEnabledInSettings, + needEnrollBiometrics = runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull() ?: false, + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index 6b648b7c0d..56b822cc8e 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -10,7 +10,7 @@ sealed class DetailsAction : Action { data class PrepareScreen( val scanResponse: ScanResponse, - val shouldSaveUserWallets: Boolean, + val initializedAppSettingsState: AppSettingsState, ) : DetailsAction() sealed class AppSettings : DetailsAction() { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index e9b44c3240..a6f2b28868 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -1,13 +1,6 @@ package com.tangem.tap.features.details.redux -import com.tangem.domain.apptheme.model.AppThemeMode -import com.tangem.tap.common.extensions.inject import com.tangem.tap.common.redux.AppState -import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.tap.store -import com.tangem.tap.tangemSdkManager -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.runBlocking import org.rekotlin.Action object DetailsReducer { @@ -36,27 +29,7 @@ private fun internalReduce(action: Action, state: AppState): DetailsState { private fun handlePrepareScreen(action: DetailsAction.PrepareScreen): DetailsState { return DetailsState( scanResponse = action.scanResponse, - appSettingsState = AppSettingsState( - isBiometricsAvailable = runBlocking { - tangemSdkManager.checkCanUseBiometry() - }, - saveWallets = action.shouldSaveUserWallets, - saveAccessCodes = runBlocking { - store.inject(DaggerGraphState::settingsRepository).shouldSaveAccessCodes() - }, - selectedAppCurrency = store.state.globalState.appCurrency, - selectedThemeMode = runBlocking { - store.inject(DaggerGraphState::appThemeModeRepository).getAppThemeMode().firstOrNull() - ?: AppThemeMode.DEFAULT - }, - isHidingEnabled = runBlocking { - store.inject(DaggerGraphState::balanceHidingRepository) - .getBalanceHidingSettings().isHidingEnabledInSettings - }, - needEnrollBiometrics = runBlocking { - runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull() ?: false - }, - ), + appSettingsState = action.initializedAppSettingsState, ) } diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/RuntimeDataStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/datastore/RuntimeDataStore.kt index db39d064d3..69fe8b7ca2 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/datastore/RuntimeDataStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/datastore/RuntimeDataStore.kt @@ -2,10 +2,11 @@ package com.tangem.datasource.local.datastore import com.tangem.datasource.local.datastore.core.StringKeyDataStore import kotlinx.coroutines.flow.* +import java.util.concurrent.ConcurrentHashMap internal class RuntimeDataStore : StringKeyDataStore { - private val store: MutableSharedFlow?> = MutableSharedFlow(replay = 1) + private val store: MutableSharedFlow?> = MutableSharedFlow(replay = 1) init { store.tryEmit(value = null) @@ -61,7 +62,7 @@ internal class RuntimeDataStore : StringKeyDataStore { override suspend fun remove(keys: Collection) { updateValue { value -> - HashMap(value.filterKeys { it !in keys }) + ConcurrentHashMap(value.filterKeys { it !in keys }) } } @@ -69,8 +70,10 @@ internal class RuntimeDataStore : StringKeyDataStore { store.emit(value = null) } - private suspend inline fun updateValue(update: (HashMap) -> HashMap) { - val storedData = store.firstOrNull() ?: hashMapOf() + private suspend inline fun updateValue( + update: (ConcurrentHashMap) -> ConcurrentHashMap, + ) { + val storedData = store.firstOrNull() ?: ConcurrentHashMap() val updatedData = update(storedData) store.emit(updatedData) diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt index be9623f89e..fd6ff690a3 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt @@ -100,7 +100,7 @@ internal class TokenListSortingOperations( private fun CryptoCurrencyStatus.getTotalBalance(): BigDecimal { val yieldBalance = value.yieldBalance as? YieldBalance.Data val totalYieldBalance = yieldBalance?.getTotalWithRewardsStakingBalance().orZero() - val totalFiatYieldBalance = if (!BlockchainUtils.isIncludeStakingTotalBalance(currency.network.id.value)) { + val totalFiatYieldBalance = if (BlockchainUtils.isIncludeStakingTotalBalance(currency.network.id.value)) { totalYieldBalance.multiply(value.fiatRate.orZero()) } else { BigDecimal.ZERO diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt index 99def3ec10..4ccf6cdd01 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt @@ -23,12 +23,12 @@ import com.tangem.features.details.utils.SocialsBuilder import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.version.AppVersionProvider import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import timber.log.Timber import javax.inject.Inject @@ -52,42 +52,45 @@ internal class DetailsModel @Inject constructor( private val params: DetailsComponent.Params = paramsContainer.require() - private val items: MutableStateFlow> = MutableStateFlow(value = persistentListOf()) + private val items: MutableStateFlow> - val state: MutableStateFlow = MutableStateFlow( - value = DetailsUM( - items = items.value, - footer = DetailsFooterUM( - socials = socialsBuilder.buildAll(), - appVersion = getAppVersion(), - ), - popBack = router::pop, - ), - ) + val state: MutableStateFlow init { // Use to save compatibility with screens that using Redux states bootstrapScreenState() + val isWalletConnectAvailable = runBlocking { + // danger region, this works immediately, but will be refactored later with WC + checkIsWalletConnectAvailableUseCase(params.userWalletId).getOrElse { + Timber.w("Unable to check WalletConnect availability: $it") + + false + } + } + + items = MutableStateFlow( + itemsBuilder.buildAll( + isWalletConnectAvailable = isWalletConnectAvailable, + onSupportClick = ::sendFeedback, + onBuyClick = ::onBuyClick, + ), + ) + + state = MutableStateFlow( + value = DetailsUM( + items = items.value, + footer = DetailsFooterUM( + socials = socialsBuilder.buildAll(), + appVersion = getAppVersion(), + ), + popBack = router::pop, + ), + ) + items .onEach(::updateState) .launchIn(modelScope) - - checkWalletConnectAvailability() - } - - private fun checkWalletConnectAvailability() = modelScope.launch { - val isWalletConnectAvailable = checkIsWalletConnectAvailableUseCase(params.userWalletId).getOrElse { - Timber.w("Unable to check WalletConnect availability: $it") - - false - } - - items.value = itemsBuilder.buildAll( - isWalletConnectAvailable = isWalletConnectAvailable, - onSupportClick = ::sendFeedback, - onBuyClick = ::onBuyClick, - ) } private fun bootstrapScreenState() { diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt index ab97ccdcdf..6e596ae2ec 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt @@ -48,9 +48,7 @@ internal class SetConfirmationStateInitTransformer( actionType = actionType, balanceState = balanceState, confirmationState = StakingStates.ConfirmationState.Data( - isPrimaryButtonEnabled = with(cryptoCurrencyStatus.value) { - sources.yieldBalanceSource.isActual() && sources.networkSource.isActual() - }, + isPrimaryButtonEnabled = false, innerState = InnerConfirmationStakingState.ASSENT, feeState = FeeState.Loading, notifications = persistentListOf(), diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 972cbd4bd7..8fbee2f5e1 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -28,9 +28,9 @@ androidxWorkManager = "2.9.0" # endregion AndroidX # region Compose -compose-runtime = "1.7.8" -compose-foundation = "1.7.8" -compose-material = "1.7.8" +compose-runtime = "1.7.4" +compose-foundation = "1.7.4" +compose-material = "1.7.4" compose-material3 = "1.3.1" compose-constraint = "1.0.1" compose-navigation = "2.7.7"