Updated on 2026-08-14
This commit is contained in:
parent
e3c0b0b311
commit
fcdfe622f9
27 changed files with 384 additions and 54 deletions
|
|
@ -28,7 +28,9 @@ dependencies {
|
|||
implementation(projects.domain.card)
|
||||
implementation(project(":domain:wallets"))
|
||||
implementation(project(":domain:wallets:models"))
|
||||
implementation(projects.domain.settings)
|
||||
implementation(projects.domain.tokens)
|
||||
|
||||
implementation(project(":common"))
|
||||
implementation(project(":core:analytics"))
|
||||
implementation(projects.core.analytics.models)
|
||||
|
|
@ -42,6 +44,7 @@ dependencies {
|
|||
implementation(project(":libs:auth"))
|
||||
implementation(project(":data:source:preferences"))
|
||||
implementation(projects.data.card)
|
||||
implementation(projects.data.settings)
|
||||
implementation(projects.data.tokens)
|
||||
implementation(projects.data.common)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.card.GetAccessCodeSavingStatusUseCase
|
||||
import com.tangem.domain.card.GetBiometricsStatusUseCase
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.card.SetAccessCodeRequestPolicyUseCase
|
||||
import com.tangem.domain.card.*
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.tap.domain.scanCard.DefaultScanCardProcessor
|
||||
import dagger.Module
|
||||
|
|
@ -43,4 +41,10 @@ internal object CardDomainModule {
|
|||
): GetAccessCodeSavingStatusUseCase {
|
||||
return GetAccessCodeSavingStatusUseCase(cardSdkConfigRepository = cardSdkConfigRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetCardWasScannedUseCase(cardRepository: CardRepository): GetCardWasScannedUseCase {
|
||||
return GetCardWasScannedUseCase(cardRepository = cardRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.settings.IsUserAlreadyRateAppUseCase
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
internal object SettingsDomainModule {
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesGetWalletsUseCase(settingsRepository: SettingsRepository): IsUserAlreadyRateAppUseCase {
|
||||
return IsUserAlreadyRateAppUseCase(settingsRepository = settingsRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.tap.common.di.domain.wallets
|
||||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
|
|
@ -11,7 +11,7 @@ import dagger.hilt.android.scopes.ViewModelScoped
|
|||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
object WalletsDomainModule {
|
||||
internal object WalletsDomainModule {
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
|
|
@ -13,10 +13,14 @@ android {
|
|||
dependencies {
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
||||
implementation(deps.tangem.card.android)
|
||||
implementation(deps.tangem.card.core)
|
||||
|
||||
implementation(projects.core.utils)
|
||||
|
||||
implementation(projects.data.source.preferences)
|
||||
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.models)
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.data.card
|
||||
|
||||
import com.tangem.data.source.preferences.PreferencesDataSource
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
internal class DefaultCardRepository(
|
||||
private val preferencesDataSource: PreferencesDataSource,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : CardRepository {
|
||||
|
||||
override suspend fun wasCardScanned(cardId: String): Boolean {
|
||||
return withContext(dispatchers.io) { preferencesDataSource.usedCardsPrefStorage.wasScanned(cardId) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
package com.tangem.data.card.di
|
||||
|
||||
import com.tangem.data.card.DefaultCardRepository
|
||||
import com.tangem.data.card.DefaultCardSdkConfigRepository
|
||||
import com.tangem.data.card.sdk.CardSdkProvider
|
||||
import com.tangem.data.source.preferences.PreferencesDataSource
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -25,4 +28,13 @@ internal object CardDataModule {
|
|||
preferencesDataSource = preferencesDataSource,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideCardRepository(
|
||||
preferencesDataSource: PreferencesDataSource,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): CardRepository {
|
||||
return DefaultCardRepository(preferencesDataSource = preferencesDataSource, dispatchers = dispatchers)
|
||||
}
|
||||
}
|
||||
1
data/settings/.gitignore
vendored
Normal file
1
data/settings/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
26
data/settings/build.gradle.kts
Normal file
26
data/settings/build.gradle.kts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
alias(deps.plugins.hilt.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.data.settings"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
||||
implementation(deps.kotlin.coroutines)
|
||||
|
||||
implementation(projects.core.utils)
|
||||
|
||||
implementation(projects.domain.settings)
|
||||
|
||||
implementation(projects.data.source.preferences)
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.data.settings
|
||||
|
||||
import com.tangem.data.source.preferences.PreferencesDataSource
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
internal class DefaultSettingsRepository(
|
||||
private val preferencesDataSource: PreferencesDataSource,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : SettingsRepository {
|
||||
|
||||
override suspend fun isUserAlreadyRateApp(): Boolean {
|
||||
return withContext(dispatchers.io) {
|
||||
preferencesDataSource.appRatingLaunchObserver.isReadyToShow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.data.settings.di
|
||||
|
||||
import com.tangem.data.settings.DefaultSettingsRepository
|
||||
import com.tangem.data.source.preferences.PreferencesDataSource
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object SettingsDataModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSettingsRepository(
|
||||
preferencesDataSource: PreferencesDataSource,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): SettingsRepository {
|
||||
return DefaultSettingsRepository(preferencesDataSource = preferencesDataSource, dispatchers = dispatchers)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.domain.card
|
||||
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
|
||||
class GetCardWasScannedUseCase(private val cardRepository: CardRepository) {
|
||||
|
||||
suspend operator fun invoke(cardId: String): Boolean = cardRepository.wasCardScanned(cardId)
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.domain.card.repository
|
||||
|
||||
interface CardRepository {
|
||||
|
||||
suspend fun wasCardScanned(cardId: String): Boolean
|
||||
}
|
||||
|
|
@ -26,4 +26,20 @@ interface CardTypesResolver {
|
|||
fun getPrimaryToken(): Token?
|
||||
|
||||
fun getBackupCardsCount(): Int
|
||||
|
||||
fun isReleaseFirmwareType(): Boolean
|
||||
|
||||
fun getRemainingSignatures(): Int?
|
||||
|
||||
fun getCardId(): String
|
||||
|
||||
fun isTestCard(): Boolean
|
||||
|
||||
fun isAttestationFailed(): Boolean
|
||||
|
||||
fun hasWalletSignedHashes(): Boolean
|
||||
|
||||
fun hasBackup(): Boolean
|
||||
|
||||
fun isBackupForbidden(): Boolean
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
|||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.operations.attestation.Attestation
|
||||
|
||||
internal class TangemCardTypesResolver(
|
||||
private val card: CardDTO,
|
||||
|
|
@ -73,6 +74,27 @@ internal class TangemCardTypesResolver(
|
|||
|
||||
override fun getBackupCardsCount(): Int = card.wallets.size
|
||||
|
||||
override fun isReleaseFirmwareType(): Boolean = card.firmwareVersion.type == FirmwareVersion.FirmwareType.Release
|
||||
|
||||
override fun getRemainingSignatures(): Int? = card.wallets.firstOrNull()?.remainingSignatures
|
||||
|
||||
override fun getCardId(): String = card.cardId
|
||||
|
||||
override fun isTestCard(): Boolean = card.isTestCard
|
||||
|
||||
override fun isAttestationFailed(): Boolean = card.attestation.status == Attestation.Status.Failed
|
||||
|
||||
override fun hasWalletSignedHashes(): Boolean {
|
||||
return card.wallets.any {
|
||||
val totalSignedHashes = it.totalSignedHashes ?: 0
|
||||
totalSignedHashes > 0
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasBackup(): Boolean = card.backupStatus != CardDTO.BackupStatus.NoBackup
|
||||
|
||||
override fun isBackupForbidden(): Boolean = !(card.settings.isBackupAllowed || card.settings.isHDWalletAllowed)
|
||||
|
||||
private fun Blockchain.Companion.fromBlockchainName(blockchainName: String): Blockchain {
|
||||
// workaround for BSC (BNB) notes cards
|
||||
return when (blockchainName) {
|
||||
|
|
|
|||
1
domain/settings/.gitignore
vendored
Normal file
1
domain/settings/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
4
domain/settings/build.gradle.kts
Normal file
4
domain/settings/build.gradle.kts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
id("configuration")
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.domain.settings
|
||||
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
|
||||
class IsUserAlreadyRateAppUseCase(private val settingsRepository: SettingsRepository) {
|
||||
|
||||
suspend operator fun invoke(): Boolean = settingsRepository.isUserAlreadyRateApp()
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.domain.settings.repositories
|
||||
|
||||
interface SettingsRepository {
|
||||
|
||||
suspend fun isUserAlreadyRateApp(): Boolean
|
||||
}
|
||||
|
|
@ -37,20 +37,21 @@ dependencies {
|
|||
kapt(deps.hilt.kapt)
|
||||
|
||||
/** Core modules */
|
||||
implementation(project(":core:featuretoggles"))
|
||||
implementation(project(":core:navigation"))
|
||||
implementation(project(":core:ui"))
|
||||
implementation(projects.core.featuretoggles)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.utils)
|
||||
|
||||
/** Feature Apis */
|
||||
implementation(project(":features:wallet:api"))
|
||||
|
||||
/** Domain modules */
|
||||
implementation(project(":common"))
|
||||
implementation(projects.common)
|
||||
implementation(projects.domain.card)
|
||||
implementation(project(":domain:legacy"))
|
||||
implementation(project(":domain:models"))
|
||||
implementation(project(":domain:wallets"))
|
||||
implementation(project(":domain:wallets:models"))
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.settings)
|
||||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
||||
/** Feature Apis */
|
||||
implementation(projects.features.wallet.api)
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -79,9 +79,10 @@ include(":domain:legacy")
|
|||
|
||||
include(":domain:core")
|
||||
include(":domain:card")
|
||||
include(":domain:settings")
|
||||
include(":domain:tokens")
|
||||
include(":domain:wallets")
|
||||
include(":domain:wallets:models")
|
||||
include(":domain:tokens")
|
||||
// endregion Domain modules
|
||||
|
||||
// region Data modules
|
||||
|
|
@ -90,3 +91,4 @@ include(":data:card")
|
|||
include(":data:tokens")
|
||||
include(":data:source:preferences")
|
||||
// endregion Data modules
|
||||
include(":data:settings")
|
||||
Loading…
Add table
Add a link
Reference in a new issue