Updated on 2026-08-14
This commit is contained in:
parent
901e46800e
commit
cb9e07b46d
3 changed files with 78 additions and 68 deletions
|
|
@ -12,6 +12,7 @@ import androidx.compose.foundation.lazy.itemsIndexed
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.rows.CornersToRound
|
||||
|
|
@ -64,6 +65,11 @@ fun LazyListScope.roundedListWithDividersItems(
|
|||
endText = row.endText.orMaskWithStars(hideEndText && row.isEndTextHideable).resolveReference(),
|
||||
cornersToRound = getCornersToRound(index, rows.size),
|
||||
iconClick = row.iconClick,
|
||||
endTextColor = if (row.isEndTextHighlighted) {
|
||||
TangemTheme.colors.text.accent
|
||||
} else {
|
||||
TangemTheme.colors.text.tertiary
|
||||
},
|
||||
showDivider = index < rows.lastIndex,
|
||||
)
|
||||
}
|
||||
|
|
@ -81,6 +87,7 @@ private fun InitialInfoContentRow(
|
|||
endText: String,
|
||||
cornersToRound: CornersToRound,
|
||||
showDivider: Boolean,
|
||||
endTextColor: Color = TangemTheme.colors.text.tertiary,
|
||||
iconClick: (() -> Unit)? = null,
|
||||
) {
|
||||
Box {
|
||||
|
|
@ -89,7 +96,7 @@ private fun InitialInfoContentRow(
|
|||
startTextColor = TangemTheme.colors.text.primary1,
|
||||
startTextStyle = TangemTheme.typography.body2,
|
||||
endText = endText,
|
||||
endTextColor = TangemTheme.colors.text.tertiary,
|
||||
endTextColor = endTextColor,
|
||||
endTextStyle = TangemTheme.typography.body2,
|
||||
cornersToRound = cornersToRound,
|
||||
iconResId = R.drawable.ic_information_24,
|
||||
|
|
@ -126,6 +133,7 @@ data class RoundedListWithDividersItemData(
|
|||
val id: Int,
|
||||
val startText: TextReference,
|
||||
val endText: TextReference,
|
||||
val isEndTextHighlighted: Boolean = false,
|
||||
val iconClick: (() -> Unit)? = null,
|
||||
val isEndTextHideable: Boolean = false,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ internal class SetInitialDataStateTransformer(
|
|||
startText = TextReference.Res(R.string.staking_details_annual_percentage_rate),
|
||||
endText = getAprRange(validators),
|
||||
iconClick = { clickIntents.onInfoClick(InfoType.ANNUAL_PERCENTAGE_RATE) },
|
||||
isEndTextHighlighted = true,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ import com.tangem.utils.coroutines.*
|
|||
import com.tangem.utils.extensions.isSingleItem
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -101,6 +102,7 @@ internal class StakingViewModel @Inject constructor(
|
|||
private val stakingFeeTransactionLoader: StakingFeeTransactionLoader.Factory,
|
||||
private val stakingBalanceUpdater: StakingBalanceUpdater.Factory,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel(), DefaultLifecycleObserver, StakingClickIntents {
|
||||
|
||||
|
|
@ -174,7 +176,8 @@ internal class StakingViewModel @Inject constructor(
|
|||
private val transactionsInProgress: CopyOnWriteArrayList<StakingTransaction> = CopyOnWriteArrayList()
|
||||
|
||||
private var approvalJobHolder: JobHolder = JobHolder()
|
||||
private var updateBalancesJobHolder: JobHolder = JobHolder()
|
||||
private var feeJobHolder: JobHolder = JobHolder()
|
||||
private var sendTransactionJobHolder = JobHolder()
|
||||
|
||||
init {
|
||||
subscribeOnSelectedAppCurrency()
|
||||
|
|
@ -184,8 +187,9 @@ internal class StakingViewModel @Inject constructor(
|
|||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
updateBalancesJobHolder.cancel()
|
||||
approvalJobHolder.cancel()
|
||||
feeJobHolder.cancel()
|
||||
sendTransactionJobHolder.cancel()
|
||||
}
|
||||
|
||||
override fun onBackClick() {
|
||||
|
|
@ -258,7 +262,7 @@ internal class StakingViewModel @Inject constructor(
|
|||
updateNotifications()
|
||||
},
|
||||
)
|
||||
}
|
||||
}.saveIn(feeJobHolder)
|
||||
}
|
||||
|
||||
private fun handleOnNextConfirmationClick() {
|
||||
|
|
@ -287,7 +291,7 @@ internal class StakingViewModel @Inject constructor(
|
|||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
},
|
||||
)
|
||||
}
|
||||
}.saveIn(sendTransactionJobHolder)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -313,12 +317,11 @@ internal class StakingViewModel @Inject constructor(
|
|||
|
||||
override fun onRefreshSwipe(isRefreshing: Boolean) {
|
||||
stateController.update(SetInitialLoadingStateTransformer(isRefreshing))
|
||||
viewModelScope.launch {
|
||||
coroutineScope.launch {
|
||||
balanceUpdater.instantUpdate()
|
||||
}.saveIn(updateBalancesJobHolder)
|
||||
.invokeOnCompletion {
|
||||
stateController.update(SetInitialLoadingStateTransformer(false))
|
||||
}
|
||||
}.invokeOnCompletion {
|
||||
stateController.update(SetInitialLoadingStateTransformer(false))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInitialInfoBannerClick() {
|
||||
|
|
@ -393,7 +396,7 @@ internal class StakingViewModel @Inject constructor(
|
|||
cryptoCurrencyStatus.currency.network.id.value,
|
||||
activeStake.pendingActions,
|
||||
)
|
||||
val isMultiplePendingActions = activeStake.pendingActions.isSingleItem().not()
|
||||
val isMultiplePendingActions = activeStake.pendingActions.size > 1
|
||||
if (isMultiplePendingActions && !isAllWithdrawActions) {
|
||||
stateController.update(
|
||||
ShowActionSelectorBottomSheetTransformer(
|
||||
|
|
@ -701,65 +704,63 @@ internal class StakingViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun subscribeOnCurrencyStatusUpdates() {
|
||||
viewModelScope.launch {
|
||||
getUserWalletUseCase(userWalletId).fold(
|
||||
ifRight = { wallet ->
|
||||
userWallet = wallet
|
||||
},
|
||||
ifLeft = {
|
||||
Timber.e(it.toString())
|
||||
stakingEventFactory.createGenericErrorAlert(it.toString())
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
},
|
||||
)
|
||||
getCurrencyStatusUpdatesUseCase(userWalletId, cryptoCurrencyId, false)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.filter { value.currentStep == StakingStep.InitialInfo }
|
||||
.onEach { maybeStatus ->
|
||||
maybeStatus.fold(
|
||||
ifRight = { status ->
|
||||
if (!isInitialInfoAnalyticSent) {
|
||||
isInitialInfoAnalyticSent = true
|
||||
val balances = status.value.yieldBalance as? YieldBalance.Data
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.StakingInfoScreenOpened(
|
||||
validatorsCount = balances?.getValidatorsCount() ?: 0,
|
||||
token = status.currency.symbol,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
feeCryptoCurrencyStatus =
|
||||
getFeePaidCryptoCurrencyStatusSyncUseCase(userWalletId, status).getOrNull()
|
||||
cryptoCurrencyStatus = status
|
||||
val isAnyTokenStaked = isAnyTokenStakedUseCase(userWalletId).getOrNull() ?: false
|
||||
|
||||
setupApprovalNeeded()
|
||||
checkIfSubtractAvailable()
|
||||
|
||||
stateController.update(
|
||||
transformer = SetInitialDataStateTransformer(
|
||||
clickIntents = this@StakingViewModel,
|
||||
yield = yield,
|
||||
isAnyTokenStaked = isAnyTokenStaked,
|
||||
isApprovalNeeded = stakingApproval is StakingApproval.Needed,
|
||||
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
|
||||
userWalletProvider = Provider { userWallet },
|
||||
appCurrencyProvider = Provider { appCurrency },
|
||||
getUserWalletUseCase(userWalletId).fold(
|
||||
ifRight = { wallet ->
|
||||
userWallet = wallet
|
||||
},
|
||||
ifLeft = {
|
||||
Timber.e(it.toString())
|
||||
stakingEventFactory.createGenericErrorAlert(it.toString())
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
},
|
||||
)
|
||||
getCurrencyStatusUpdatesUseCase(userWalletId, cryptoCurrencyId, false)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.filter { value.currentStep == StakingStep.InitialInfo }
|
||||
.onEach { maybeStatus ->
|
||||
maybeStatus.fold(
|
||||
ifRight = { status ->
|
||||
if (!isInitialInfoAnalyticSent) {
|
||||
isInitialInfoAnalyticSent = true
|
||||
val balances = status.value.yieldBalance as? YieldBalance.Data
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.StakingInfoScreenOpened(
|
||||
validatorsCount = balances?.getValidatorsCount() ?: 0,
|
||||
token = status.currency.symbol,
|
||||
),
|
||||
)
|
||||
},
|
||||
ifLeft = { error ->
|
||||
Timber.e(error.toString())
|
||||
stakingEventFactory.createGenericErrorAlert(error.toString())
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
},
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
}
|
||||
|
||||
feeCryptoCurrencyStatus =
|
||||
getFeePaidCryptoCurrencyStatusSyncUseCase(userWalletId, status).getOrNull()
|
||||
cryptoCurrencyStatus = status
|
||||
val isAnyTokenStaked = isAnyTokenStakedUseCase(userWalletId).getOrNull() ?: false
|
||||
|
||||
setupApprovalNeeded()
|
||||
checkIfSubtractAvailable()
|
||||
|
||||
stateController.update(
|
||||
transformer = SetInitialDataStateTransformer(
|
||||
clickIntents = this@StakingViewModel,
|
||||
yield = yield,
|
||||
isAnyTokenStaked = isAnyTokenStaked,
|
||||
isApprovalNeeded = stakingApproval is StakingApproval.Needed,
|
||||
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
|
||||
userWalletProvider = Provider { userWallet },
|
||||
appCurrencyProvider = Provider { appCurrency },
|
||||
),
|
||||
)
|
||||
},
|
||||
ifLeft = { error ->
|
||||
Timber.e(error.toString())
|
||||
stakingEventFactory.createGenericErrorAlert(error.toString())
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
},
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun subscribeOnBalanceHiding() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue