Updated on 2026-08-14
This commit is contained in:
parent
e3c0b0b311
commit
fcdfe622f9
27 changed files with 384 additions and 54 deletions
|
|
@ -15,7 +15,6 @@ import androidx.navigation.compose.rememberNavController
|
|||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.navigation.NavigationStateHolder
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.WalletFragment
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensScreen
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensViewModel
|
||||
|
|
@ -35,29 +34,27 @@ internal class DefaultWalletRouter(private val navigationStateHolder: Navigation
|
|||
override fun Initialize(fragmentManager: FragmentManager) {
|
||||
this.fragmentManager = fragmentManager
|
||||
|
||||
TangemTheme {
|
||||
NavHost(
|
||||
navController = rememberNavController().apply { navController = this },
|
||||
startDestination = WalletScreens.WALLET.name,
|
||||
) {
|
||||
composable(WalletScreens.WALLET.name) {
|
||||
val viewModel = hiltViewModel<WalletViewModel>().apply { router = this@DefaultWalletRouter }
|
||||
LocalLifecycleOwner.current.lifecycle.addObserver(observer = viewModel)
|
||||
NavHost(
|
||||
navController = rememberNavController().apply { navController = this },
|
||||
startDestination = WalletScreens.WALLET.name,
|
||||
) {
|
||||
composable(WalletScreens.WALLET.name) {
|
||||
val viewModel = hiltViewModel<WalletViewModel>().apply { router = this@DefaultWalletRouter }
|
||||
LocalLifecycleOwner.current.lifecycle.addObserver(observer = viewModel)
|
||||
|
||||
WalletScreen(state = viewModel.uiState)
|
||||
}
|
||||
WalletScreen(state = viewModel.uiState)
|
||||
}
|
||||
|
||||
composable(WalletScreens.ORGANIZE_TOKENS.name) {
|
||||
BackHandler(onBack = ::popBackStack)
|
||||
composable(WalletScreens.ORGANIZE_TOKENS.name) {
|
||||
BackHandler(onBack = ::popBackStack)
|
||||
|
||||
val viewModel: OrganizeTokensViewModel = hiltViewModel<OrganizeTokensViewModel>()
|
||||
.apply { router = this@DefaultWalletRouter }
|
||||
val viewModel: OrganizeTokensViewModel = hiltViewModel<OrganizeTokensViewModel>()
|
||||
.apply { router = this@DefaultWalletRouter }
|
||||
|
||||
OrganizeTokensScreen(
|
||||
modifier = Modifier.systemBarsPadding(),
|
||||
state = viewModel.uiState,
|
||||
)
|
||||
}
|
||||
OrganizeTokensScreen(
|
||||
modifier = Modifier.systemBarsPadding(),
|
||||
state = viewModel.uiState,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,12 +63,29 @@ sealed class WalletNotification(open val state: NotificationState) {
|
|||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* "Remaining signatures left" notification
|
||||
*
|
||||
* @param count number of remaining signatures
|
||||
*/
|
||||
class RemainingSignaturesLeft(count: Int) : WalletNotification(
|
||||
state = NotificationState.Simple(
|
||||
title = TextReference.Res(id = R.string.common_warning),
|
||||
subtitle = TextReference.Res(
|
||||
id = R.string.warning_low_signatures_format,
|
||||
formatArgs = WrappedList(data = listOf(count)),
|
||||
),
|
||||
iconResId = R.drawable.ic_alert_circle_24,
|
||||
tint = TangemColorPalette.Amaranth,
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* "Wallet already signed hashes" notification
|
||||
*
|
||||
* @property onClick lambda be invoked when notification is clicked
|
||||
*/
|
||||
data class WalletAlreadySignedHashes(override val onClick: () -> Unit) : Clickable, WalletNotification(
|
||||
data class AlreadyToppedUpAndSignedHashes(override val onClick: () -> Unit) : Clickable, WalletNotification(
|
||||
state = NotificationState.Clickable(
|
||||
title = TextReference.Res(id = R.string.common_warning),
|
||||
subtitle = TextReference.Res(id = R.string.alert_card_signed_transactions),
|
||||
|
|
@ -83,7 +100,7 @@ sealed class WalletNotification(open val state: NotificationState) {
|
|||
*
|
||||
* @property onClick lambda be invoked when notification is clicked
|
||||
*/
|
||||
data class MultiWalletAlreadySignedHashes(override val onClick: () -> Unit) : Clickable, WalletNotification(
|
||||
data class SignedTransactionsInThePast(override val onClick: () -> Unit) : Clickable, WalletNotification(
|
||||
state = NotificationState.Clickable(
|
||||
title = TextReference.Res(
|
||||
id = R.string.warning_important_security_info,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ internal class WalletStateFactory(
|
|||
walletsListConfig = createWalletsListConfig(wallets),
|
||||
pullToRefreshConfig = createPullToRefreshConfig(),
|
||||
contentItems = persistentListOf(),
|
||||
notifications = persistentListOf(), // TODO: create notifications
|
||||
notifications = persistentListOf(),
|
||||
bottomSheet = WalletBottomSheetConfig(
|
||||
// TODO: check notifications
|
||||
isShow = false,
|
||||
|
|
@ -58,7 +58,7 @@ internal class WalletStateFactory(
|
|||
walletsListConfig = createWalletsListConfig(wallets),
|
||||
pullToRefreshConfig = createPullToRefreshConfig(),
|
||||
contentItems = persistentListOf(),
|
||||
notifications = persistentListOf(), // TODO: create notifications
|
||||
notifications = persistentListOf(),
|
||||
bottomSheet = WalletBottomSheetConfig(
|
||||
// TODO: check notifications
|
||||
isShow = false,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import androidx.compose.foundation.lazy.itemsIndexed
|
|||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||
import androidx.compose.material.pullrefresh.PullRefreshState
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.material3.*
|
||||
|
|
@ -40,6 +41,7 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletsList
|
|||
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.TransactionsBlockGroupTitle
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.TransactionsBlockTitle
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletContentItemDecoration
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.utils.ScrollOffsetCollector
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.utils.changeWalletAnimator
|
||||
|
||||
/**
|
||||
|
|
@ -54,13 +56,13 @@ import com.tangem.feature.wallet.presentation.wallet.ui.utils.changeWalletAnimat
|
|||
@Composable
|
||||
internal fun WalletScreen(state: WalletStateHolder) {
|
||||
BackHandler(onBack = state.onBackClick)
|
||||
val walletsListState = rememberLazyListState()
|
||||
|
||||
Scaffold(
|
||||
topBar = { WalletTopBar(config = state.topBarConfig) },
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
) { scaffoldPaddings ->
|
||||
|
||||
val walletsListState = rememberLazyListState()
|
||||
val changeableItemModifier = Modifier.changeWalletAnimator(walletsListState)
|
||||
val pullRefreshState = rememberPullRefreshState(
|
||||
refreshing = state.pullToRefreshConfig.isRefreshing,
|
||||
|
|
@ -153,8 +155,8 @@ internal fun WalletScreen(state: WalletStateHolder) {
|
|||
}
|
||||
}
|
||||
|
||||
PullRefreshIndicator(
|
||||
refreshing = state.pullToRefreshConfig.isRefreshing,
|
||||
PullToRefreshIndicator(
|
||||
isRefreshing = state.pullToRefreshConfig.isRefreshing,
|
||||
state = pullRefreshState,
|
||||
modifier = Modifier.align(Alignment.TopCenter),
|
||||
)
|
||||
|
|
@ -164,6 +166,21 @@ internal fun WalletScreen(state: WalletStateHolder) {
|
|||
state.bottomSheet?.let { bottomSheetConfig ->
|
||||
if (bottomSheetConfig.isShow) WalletBottomSheet(config = bottomSheetConfig)
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = walletsListState, key2 = state.walletsListConfig.onWalletChange) {
|
||||
snapshotFlow { walletsListState.layoutInfo.visibleItemsInfo }
|
||||
.collect(collector = ScrollOffsetCollector(callback = state.walletsListConfig.onWalletChange))
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
private fun PullToRefreshIndicator(isRefreshing: Boolean, state: PullRefreshState, modifier: Modifier = Modifier) {
|
||||
PullRefreshIndicator(
|
||||
refreshing = isRefreshing,
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ import androidx.compose.foundation.lazy.LazyRow
|
|||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -20,7 +18,6 @@ import androidx.compose.ui.unit.dp
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletsListConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.utils.ScrollOffsetCollector
|
||||
|
||||
/**
|
||||
* Wallets list component
|
||||
|
|
@ -47,11 +44,6 @@ internal fun WalletsList(config: WalletsListConfig, lazyListState: LazyListState
|
|||
WalletCard(state = state, modifier = Modifier.width(itemWidth))
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(lazyListState) {
|
||||
snapshotFlow { lazyListState.layoutInfo.visibleItemsInfo }
|
||||
.collect(collector = ScrollOffsetCollector(callback = config.onWalletChange))
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels
|
||||
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletNotification
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
internal class WalletNotificationsListFactory(
|
||||
private val wasCardScannedCallback: suspend (String) -> Boolean,
|
||||
private val isUserAlreadyRateAppCallback: suspend () -> Boolean,
|
||||
private val onWalletAlreadySignedHashesClick: () -> Unit,
|
||||
private val onMultiWalletAlreadySignedHashesClick: () -> Unit,
|
||||
private val onBackupCardClick: () -> Unit,
|
||||
private val hasUnreachableNetworksCallback: () -> Boolean,
|
||||
private val onLikeTangemAppClick: () -> Unit,
|
||||
) {
|
||||
|
||||
fun create(cardTypesResolver: CardTypesResolver): Flow<ImmutableList<WalletNotification>> {
|
||||
// TODO: [REDACTED_JIRA] order
|
||||
return flow {
|
||||
emit(
|
||||
buildList {
|
||||
if (cardTypesResolver.isTestCard()) {
|
||||
add(element = WalletNotification.TestCard)
|
||||
return@buildList
|
||||
}
|
||||
|
||||
addRemainingSignaturesLeftNotifications(cardTypesResolver)
|
||||
|
||||
if (!cardTypesResolver.isReleaseFirmwareType()) {
|
||||
add(element = WalletNotification.DevCard)
|
||||
} else {
|
||||
addReleaseSpecialNotifications(cardTypesResolver)
|
||||
}
|
||||
|
||||
// TODO: [REDACTED_JIRA] - DemoModeDatasource
|
||||
|
||||
if (hasUnreachableNetworksCallback()) {
|
||||
add(element = WalletNotification.UnreachableNetworks)
|
||||
}
|
||||
|
||||
if (!cardTypesResolver.isBackupForbidden() && !cardTypesResolver.hasBackup()) {
|
||||
add(element = WalletNotification.BackupCard(onClick = onBackupCardClick))
|
||||
}
|
||||
|
||||
/* TODO: [REDACTED_JIRA]
|
||||
* List<WalletStoreModel>
|
||||
* .filter { store ->
|
||||
* store.walletsData.any { it.status is WalletDataModel.MissedDerivation }
|
||||
* }
|
||||
*/
|
||||
|
||||
if (isUserAlreadyRateAppCallback()) {
|
||||
add(element = WalletNotification.LikeTangemApp(onClick = onLikeTangemAppClick))
|
||||
}
|
||||
}.toImmutableList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addRemainingSignaturesLeftNotifications(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
) {
|
||||
val remainingSignatures = cardTypesResolver.getRemainingSignatures()
|
||||
if (remainingSignatures != null && remainingSignatures <= MAX_REMAINING_SIGNATURES_COUNT) {
|
||||
add(element = WalletNotification.RemainingSignaturesLeft(remainingSignatures))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun MutableList<WalletNotification>.addReleaseSpecialNotifications(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
) {
|
||||
// TODO: [REDACTED_JIRA] !isDemo
|
||||
if (!wasCardScannedCallback(cardTypesResolver.getCardId()) && cardTypesResolver.isMultiwalletAllowed()) {
|
||||
if (cardTypesResolver.isBackupForbidden() && cardTypesResolver.hasWalletSignedHashes()) {
|
||||
add(
|
||||
element = WalletNotification.SignedTransactionsInThePast(
|
||||
onClick = onMultiWalletAlreadySignedHashesClick,
|
||||
),
|
||||
)
|
||||
} else if (cardTypesResolver.hasWalletSignedHashes()) {
|
||||
add(
|
||||
element = WalletNotification.AlreadyToppedUpAndSignedHashes(
|
||||
onClick = onWalletAlreadySignedHashesClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (cardTypesResolver.isAttestationFailed()) {
|
||||
add(element = WalletNotification.CardVerificationFailed)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MAX_REMAINING_SIGNATURES_COUNT = 10
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue