diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt index e95ba41f1f..f9f50d8d05 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt @@ -27,7 +27,6 @@ import com.tangem.tap.features.saveWallet.ui.SaveWalletBottomSheetFragment import com.tangem.tap.features.send.ui.SendFragment import com.tangem.tap.features.shop.ui.ShopFragment import com.tangem.tap.features.tokens.impl.presentation.TokensListFragment -import com.tangem.tap.features.walletSelector.ui.WalletSelectorBottomSheetFragment import com.tangem.tap.features.welcome.ui.WelcomeFragment import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.store @@ -177,7 +176,6 @@ private fun fragmentFactory(screen: AppScreen): Fragment { AppScreen.Swap -> SwapFragment() AppScreen.Welcome -> WelcomeFragment() AppScreen.SaveWallet -> SaveWalletBottomSheetFragment() - AppScreen.WalletSelector -> WalletSelectorBottomSheetFragment() AppScreen.AppCurrencySelector -> AppCurrencySelectorFragment() AppScreen.ModalNotification -> ModalNotificationBottomSheetFragment() } diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt index 1af312eb52..a1232dd031 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt @@ -15,7 +15,6 @@ import com.tangem.tap.features.send.redux.reducers.SendScreenReducer import com.tangem.tap.features.shop.redux.ShopReducer import com.tangem.tap.features.signin.redux.SignInReducer import com.tangem.tap.features.tokens.legacy.redux.TokensReducer -import com.tangem.tap.features.walletSelector.redux.WalletSelectorReducer import com.tangem.tap.features.welcome.redux.WelcomeReducer import com.tangem.tap.proxy.AppStateHolder import com.tangem.tap.proxy.redux.DaggerGraphReducer @@ -41,7 +40,6 @@ fun appReducer(action: Action, state: AppState?, appStateHolder: AppStateHolder) shopState = ShopReducer.reduce(action, state.shopState), welcomeState = WelcomeReducer.reduce(action, state), saveWalletState = SaveWalletReducer.reduce(action, state), - walletSelectorState = WalletSelectorReducer.reduce(action, state), signInState = SignInReducer.reduce(action, state), daggerGraphState = DaggerGraphReducer.reduce(action, state), ) diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index a152d1c585..247d0c45aa 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -35,8 +35,6 @@ import com.tangem.tap.features.signin.redux.SignInMiddleware import com.tangem.tap.features.signin.redux.SignInState import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware import com.tangem.tap.features.tokens.legacy.redux.TokensState -import com.tangem.tap.features.walletSelector.redux.WalletSelectorMiddleware -import com.tangem.tap.features.walletSelector.redux.WalletSelectorState import com.tangem.tap.features.welcome.redux.WelcomeMiddleware import com.tangem.tap.features.welcome.redux.WelcomeState import com.tangem.tap.proxy.redux.DaggerGraphMiddleware @@ -61,7 +59,6 @@ data class AppState( val shopState: ShopState = ShopState(), val welcomeState: WelcomeState = WelcomeState(), val saveWalletState: SaveWalletState = SaveWalletState(), - val walletSelectorState: WalletSelectorState = WalletSelectorState(), val signInState: SignInState = SignInState(), val daggerGraphState: DaggerGraphState = DaggerGraphState(), ) : StateType { @@ -99,7 +96,6 @@ data class AppState( ShopMiddleware().shopMiddleware, WelcomeMiddleware().middleware, SaveWalletMiddleware().middleware, - WalletSelectorMiddleware().middleware, LockUserWalletsTimerMiddleware().middleware, AccessCodeRequestPolicyMiddleware().middleware, SignInMiddleware.middleware, diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index dd3a911708..4a83bd8b41 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -36,7 +36,6 @@ import com.tangem.tap.domain.userWalletList.di.provideRuntimeImplementation import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction -import com.tangem.tap.features.walletSelector.redux.WalletSelectorAction import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn @@ -234,7 +233,6 @@ class DetailsMiddleware { is DetailsAction.AppSettings.ChangeAppCurrency -> { store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrency)) store.dispatch(DetailsAction.ChangeAppCurrency(action.fiatCurrency)) - store.dispatch(WalletSelectorAction.ChangeAppCurrency(action.fiatCurrency)) } is DetailsAction.AppSettings.SwitchPrivacySetting.Success, is DetailsAction.AppSettings.SwitchPrivacySetting.Failure, diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/UserWalletModel.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/UserWalletModel.kt deleted file mode 100644 index d1300ffa43..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/UserWalletModel.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.tangem.tap.features.walletSelector.redux - -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.tap.domain.model.TotalFiatBalance - -data class UserWalletModel( - val id: UserWalletId, - val name: String, - val artworkUrl: String, - val type: Type, - val fiatBalance: TotalFiatBalance, - val isLocked: Boolean, -) { - sealed interface Type { - data class SingleCurrency( - val blockchainName: String, - ) : Type - - data class MultiCurrency( - val cardsInWallet: Int, - val tokensCount: Int, - ) : Type - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt deleted file mode 100644 index 9acb28b1d6..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.tangem.tap.features.walletSelector.redux - -import com.tangem.common.core.TangemError -import com.tangem.domain.wallets.models.UserWallet -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.tap.common.entities.FiatCurrency -import com.tangem.tap.domain.model.WalletStoreModel -import org.rekotlin.Action - -internal sealed interface WalletSelectorAction : Action { - data class UserWalletsLoaded( - val userWallets: List, - ) : WalletSelectorAction - - data class SelectedWalletChanged( - val selectedWallet: UserWallet, - ) : WalletSelectorAction - - data class IsLockedChanged( - val isLocked: Boolean, - ) : WalletSelectorAction - - data class WalletStoresChanged( - val walletsStores: Map>, - ) : WalletSelectorAction - - data class BalancesLoaded( - val userWalletModels: List, - ) : WalletSelectorAction - - object UnlockWithBiometry : WalletSelectorAction { - object Success : WalletSelectorAction - data class Error(val error: TangemError) : WalletSelectorAction - } - - data class SelectWallet( - val userWalletId: UserWalletId, - val sendAnalyticsEvent: Boolean = false, - ) : WalletSelectorAction - - data class RenameWallet( - val userWalletId: UserWalletId, - val newName: String, - ) : WalletSelectorAction - - data class RemoveWallets( - val userWalletsIds: List, - ) : WalletSelectorAction - - object AddWallet : WalletSelectorAction { - object Success : WalletSelectorAction - data class Error(val error: TangemError) : WalletSelectorAction - } - - data class ChangeAppCurrency( - val fiatCurrency: FiatCurrency, - ) : WalletSelectorAction - - object CloseError : WalletSelectorAction - - object ClearUserWallets : WalletSelectorAction -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt deleted file mode 100644 index 1593e811f9..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ /dev/null @@ -1,397 +0,0 @@ -package com.tangem.tap.features.walletSelector.redux - -import com.tangem.common.* -import com.tangem.common.core.TangemSdkError -import com.tangem.core.analytics.Analytics -import com.tangem.core.navigation.AppScreen -import com.tangem.core.navigation.NavigationAction -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.userwallets.UserWalletBuilder -import com.tangem.domain.userwallets.UserWalletIdBuilder -import com.tangem.domain.wallets.legacy.unlockIfLockable -import com.tangem.domain.wallets.models.UserWallet -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.tap.* -import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.Basic -import com.tangem.tap.common.analytics.events.MyWallets -import com.tangem.tap.common.extensions.dispatchOnMain -import com.tangem.tap.common.extensions.dispatchWithMain -import com.tangem.tap.common.extensions.onUserWalletSelected -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.domain.model.TotalFiatBalance -import com.tangem.tap.domain.model.WalletStoreModel -import com.tangem.tap.proxy.redux.DaggerGraphState -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.launch -import org.rekotlin.Middleware -import timber.log.Timber - -// Refactoring is coming -@Suppress("LargeClass") -internal class WalletSelectorMiddleware { - val middleware: Middleware = { _, appStateProvider -> - { next -> - { action -> - val appState = appStateProvider() - if (action is WalletSelectorAction && appState != null) { - handleAction(action, appState.walletSelectorState) - } - next(action) - } - } - } - - private fun handleAction(action: WalletSelectorAction, state: WalletSelectorState) { - when (action) { - is WalletSelectorAction.UserWalletsLoaded -> { - fetchWalletStores(action.userWallets) - } - is WalletSelectorAction.WalletStoresChanged -> { - updateBalances(action.walletsStores, state) - } - is WalletSelectorAction.UnlockWithBiometry -> { - unlockWallets() - } - is WalletSelectorAction.AddWallet -> { - addWallet() - } - is WalletSelectorAction.SelectWallet -> { - selectWallet(action.userWalletId) - } - is WalletSelectorAction.RemoveWallets -> { - deleteWallets(action.userWalletsIds, state) - } - is WalletSelectorAction.RenameWallet -> { - renameWallet(action.userWalletId, action.newName) - } - is WalletSelectorAction.ChangeAppCurrency -> { - refreshUserWalletsAmounts() - } - is WalletSelectorAction.ClearUserWallets -> { - clearUserWalletsAndCloseError() - } - is WalletSelectorAction.AddWallet.Success, - is WalletSelectorAction.AddWallet.Error, - is WalletSelectorAction.SelectedWalletChanged, - is WalletSelectorAction.UnlockWithBiometry.Error, - is WalletSelectorAction.UnlockWithBiometry.Success, - is WalletSelectorAction.BalancesLoaded, - is WalletSelectorAction.IsLockedChanged, - is WalletSelectorAction.CloseError, - -> Unit - } - } - - private fun fetchWalletStores(userWallets: List) { - scope.launch { - walletStoresManager.fetch(userWallets) - .doOnFailure { error -> - Timber.e(error, "Unable to fetch wallet stores") - } - } - } - - private fun updateBalances( - updatedWalletStores: Map>, - state: WalletSelectorState, - ) { - if (updatedWalletStores.isNotEmpty()) { - scope.launch(Dispatchers.Default) { - val updatedWallets = state.wallets.calculateBalanceAndUpdateWalletStores(updatedWalletStores) - if (updatedWallets != state.wallets) { - store.dispatchOnMain(WalletSelectorAction.BalancesLoaded(updatedWallets)) - } - } - } - } - - private fun unlockWallets() { - Analytics.send(MyWallets.Button.UnlockWithBiometrics()) - - scope.launch { - userWalletsListManager.unlockIfLockable() - .doOnFailure { error -> - Timber.e(error, "Unable to unlock all user wallets") - store.dispatchOnMain(WalletSelectorAction.UnlockWithBiometry.Error(error)) - } - .doOnSuccess { - store.dispatchOnMain(WalletSelectorAction.UnlockWithBiometry.Success) - } - } - } - - private fun addWallet() = scope.launch { - Analytics.send(MyWallets.Button.ScanNewCard()) - - val cardSdkConfigRepository = store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository) - - val prevUseBiometricsForAccessCode = cardSdkConfigRepository.isBiometricsRequestPolicy() - - // Update access code policy for access code saving when a card was scanned - cardSdkConfigRepository.setAccessCodeRequestPolicy( - isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes, - ) - - store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan( - analyticsEvent = Basic.CardWasScanned(AnalyticsParam.ScannedFrom.MyWallets), - onWalletNotCreated = { - // No need to rollback policy, continue with the policy set before the card scan - store.dispatchOnMain(WalletSelectorAction.AddWallet.Success) - store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet)) - }, - disclaimerWillShow = { - store.dispatchOnMain(NavigationAction.PopBackTo()) - }, - onSuccess = { scanResponse -> - saveUserWalletAndPopBackToWalletScreen(scanResponse) - .doOnFailure { error -> - // Rollback policy if card saving was failed - cardSdkConfigRepository.setAccessCodeRequestPolicy(prevUseBiometricsForAccessCode) - Timber.e(error, "Unable to save user wallet") - store.dispatchOnMain(WalletSelectorAction.AddWallet.Error(error)) - } - }, - onFailure = { error -> - // Rollback policy if card scanning was failed - cardSdkConfigRepository.setAccessCodeRequestPolicy(prevUseBiometricsForAccessCode) - Timber.e(error, "Unable to scan card") - store.dispatchOnMain(WalletSelectorAction.AddWallet.Error(error)) - }, - ) - } - - private suspend fun saveUserWalletAndPopBackToWalletScreen(scanResponse: ScanResponse): CompletionResult { - val userWallet = UserWalletBuilder(scanResponse).build() - ?: return CompletionResult.Failure(TangemSdkError.WalletIsNotCreated()) - - return userWalletsListManager.save(userWallet) - .doOnSuccess { - store.dispatchOnMain(WalletSelectorAction.AddWallet.Success) - store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet)) - store.onUserWalletSelected(userWallet) - } - } - - private fun selectWallet(userWalletId: UserWalletId) { - scope.launch { - userWalletsListManager.get(userWalletId) - .flatMap { userWallet -> - if (userWallet.isLocked) { - unlockUserWalletWithScannedCard(userWallet) - } else { - userWalletsListManager.select(userWalletId) - } - } - .doOnFailure { error -> - Timber.e( - error, - """ - Unable to select user wallet - |- Wallet ID to select: $userWalletId - """.trimIndent(), - ) - } - .doOnSuccess { - val selectedUserWallet = userWalletsListManager.selectedUserWalletSync - if (selectedUserWallet != null) { - store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet)) - store.onUserWalletSelected( - userWallet = selectedUserWallet, - sendAnalyticsEvent = true, - ) - } - } - } - } - - private suspend fun unlockUserWalletWithScannedCard(userWallet: UserWallet): CompletionResult { - Analytics.send(MyWallets.Button.WalletUnlockTapped()) - tangemSdkManager.changeDisplayedCardIdNumbersCount(userWallet.scanResponse) - return store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan() - .map { scanResponse -> - val scannedUserWalletId = UserWalletIdBuilder.scanResponse(scanResponse).build() - if (scannedUserWalletId == userWallet.walletId) { - userWallet.updateCardWallets(scanResponse) - } else { - // TODO: Display error - Timber.e( - """ - Unable to unlock and select user wallet - |- Excepted ID: ${userWallet.walletId} - |- Received ID: $scannedUserWalletId - """.trimIndent(), - ) - error("Wrong card") - } - } - .flatMap { updatedUserWallet -> - userWalletsListManager.save(updatedUserWallet, canOverride = true) - } - .doOnFailure { - tangemSdkManager.changeDisplayedCardIdNumbersCount( - scanResponse = userWalletsListManager.selectedUserWalletSync?.scanResponse, - ) - } - } - - private fun UserWallet.updateCardWallets(scanResponse: ScanResponse): UserWallet { - return this.copy( - scanResponse = this.scanResponse.copy( - card = this.scanResponse.card.copy( - wallets = scanResponse.card.wallets, - ), - ), - ) - } - - private fun deleteWallets(userWalletsIds: List, state: WalletSelectorState) { - Analytics.send(MyWallets.Button.DeleteWalletTapped()) - - scope.launch { - when (userWalletsIds.size) { - state.wallets.size -> clearUserWalletsAndPopBackToHomeScreen() - else -> deleteUserWallets( - userWalletsIds = userWalletsIds, - currentSelectedWalletId = state.selectedWalletId, - ) - } - .doOnFailure { error -> - Timber.e( - error, - """ - Unable to delete user wallets - |- Wallets IDs to delete: $userWalletsIds - |- Current wallets IDs: ${state.wallets.map { it.id }} - """.trimIndent(), - ) - } - } - } - - private fun renameWallet(userWalletId: UserWalletId, newName: String) { - scope.launch { - userWalletsListManager.update(userWalletId) { it.copy(name = newName) } - .doOnFailure { error -> - Timber.e( - error, - """ - Unable to rename user wallet - |- Wallet ID: $userWalletId - |- New name: $newName - """.trimIndent(), - ) - } - } - } - - private fun refreshUserWalletsAmounts() { - val featureToggles = store.state.daggerGraphState.get(DaggerGraphState::walletFeatureToggles) - if (featureToggles.isRedesignedScreenEnabled) return - - scope.launch { - walletStoresManager.updateAmounts( - userWallets = userWalletsListManager.userWallets.firstOrNull().orEmpty(), - ) - .doOnFailure { error -> - Timber.e(error, "Unable to refresh user wallets amounts") - } - } - } - - private fun clearUserWalletsAndCloseError() = scope.launch { - clearUserWallets() - .doOnSuccess { - store.dispatchWithMain(WalletSelectorAction.CloseError) - popBackToHome() - } - .doOnFailure { e -> - Timber.e(e, "Unable to clear user wallets") - } - } - - private suspend fun clearUserWalletsAndPopBackToHomeScreen(): CompletionResult { - return clearUserWallets() - .doOnSuccess { popBackToHome() } - } - - private suspend fun clearUserWallets(): CompletionResult { - return userWalletsListManager.clear() - .flatMap { walletStoresManager.clear() } - .flatMap { tangemSdkManager.clearSavedUserCodes() } - } - - private suspend fun popBackToHome() { - // !!! Workaround !!! - store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Wallet)) - delay(timeMillis = 280) - store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Home)) - } - - private suspend fun deleteUserWallets( - userWalletsIds: List, - currentSelectedWalletId: UserWalletId?, - ): CompletionResult { - return userWalletsListManager.delete(userWalletsIds) - .flatMap { walletStoresManager.delete(userWalletsIds) } - .flatMap { deleteAccessCodes(userWalletsIds) } - .doOnSuccess { - val selectedUserWallet = userWalletsListManager.selectedUserWalletSync - - when { - selectedUserWallet == null -> { - store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Welcome)) - } - currentSelectedWalletId != selectedUserWallet.walletId -> { - store.onUserWalletSelected( - userWallet = selectedUserWallet, - sendAnalyticsEvent = true, - ) - } - } - } - } - - private suspend fun deleteAccessCodes(userWalletsIds: List): CompletionResult { - val cardsIds = userWalletsListManager.userWallets.firstOrNull() - ?.asSequence() - ?.filter { it.walletId in userWalletsIds } - ?.flatMap { it.cardsInWallet } - ?.toSet() - - return if (cardsIds.isNullOrEmpty()) { - CompletionResult.Success(Unit) - } else { - tangemSdkManager.deleteSavedUserCodes(cardsIds.toSet()) - } - } - - private suspend fun List.calculateBalanceAndUpdateWalletStores( - walletStores: Map>, - ): List { - return this - .associateWith { walletStores[it.id] } - .map { (wallet, walletStores) -> - wallet.calculateBalanceAndUpdateWalletStores(walletStores) - } - } - - private suspend fun UserWalletModel.calculateBalanceAndUpdateWalletStores( - walletStores: List?, - ): UserWalletModel { - return this.copy( - type = when (type) { - is UserWalletModel.Type.MultiCurrency -> type.copy( - tokensCount = walletStores?.flatMap { it.walletsData }?.size ?: 0, - ) - is UserWalletModel.Type.SingleCurrency -> type - }, - fiatBalance = totalFiatBalanceCalculator.calculate( - walletStores = walletStores.orEmpty(), - initial = TotalFiatBalance.Loading, - ), - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt deleted file mode 100644 index 13daba6567..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt +++ /dev/null @@ -1,106 +0,0 @@ -package com.tangem.tap.features.walletSelector.redux - -import com.tangem.domain.common.util.cardTypesResolver -import com.tangem.domain.models.scan.CardDTO -import com.tangem.domain.wallets.models.UserWallet -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.domain.model.TotalFiatBalance -import org.rekotlin.Action - -internal object WalletSelectorReducer { - fun reduce(action: Action, state: AppState): WalletSelectorState { - return if (action is WalletSelectorAction) { - internalReduce(action, state.walletSelectorState) - } else { - state.walletSelectorState - } - } - - @Suppress("ComplexMethod") - private fun internalReduce(action: WalletSelectorAction, state: WalletSelectorState): WalletSelectorState { - return when (action) { - is WalletSelectorAction.UserWalletsLoaded -> state.copy( - wallets = action.userWallets.updateWalletsModels(state.wallets), - ) - is WalletSelectorAction.SelectedWalletChanged -> state.copy( - selectedWalletId = action.selectedWallet.walletId, - ) - is WalletSelectorAction.IsLockedChanged -> state.copy( - isLocked = action.isLocked, - ) - is WalletSelectorAction.BalancesLoaded -> state.copy( - wallets = action.userWalletModels, - ) - is WalletSelectorAction.CloseError -> state.copy(error = null) - is WalletSelectorAction.UnlockWithBiometry -> state.copy( - isUnlockInProgress = true, - ) - is WalletSelectorAction.UnlockWithBiometry.Error -> state.copy( - isUnlockInProgress = false, - error = action.error, - ) - is WalletSelectorAction.UnlockWithBiometry.Success -> state.copy( - isUnlockInProgress = false, - ) - is WalletSelectorAction.AddWallet -> state.copy( - isCardSavingInProgress = true, - ) - is WalletSelectorAction.AddWallet.Error -> state.copy( - isCardSavingInProgress = false, - error = action.error, - ) - is WalletSelectorAction.AddWallet.Success -> state.copy( - isCardSavingInProgress = false, - ) - is WalletSelectorAction.ChangeAppCurrency -> state.copy( - fiatCurrency = action.fiatCurrency, - ) - is WalletSelectorAction.WalletStoresChanged, - is WalletSelectorAction.SelectWallet, - is WalletSelectorAction.RemoveWallets, - is WalletSelectorAction.RenameWallet, - is WalletSelectorAction.ClearUserWallets, - -> state - } - } - - private fun List.updateWalletsModels(prevWallets: List): List { - return this.map { userWallet -> - prevWallets - .find { it.id == userWallet.walletId } - ?.let { - it.copy( - name = userWallet.name, - artworkUrl = userWallet.artworkUrl, - isLocked = userWallet.isLocked, - type = userWallet.getType(prevType = it.type), - ) - } - ?: with(userWallet) { - UserWalletModel( - id = walletId, - name = name, - artworkUrl = artworkUrl, - type = getType(), - fiatBalance = TotalFiatBalance.Loading, - isLocked = isLocked, - ) - } - } - } - - private fun UserWallet.getType(prevType: UserWalletModel.Type? = null): UserWalletModel.Type { - return if (isMultiCurrency) { - UserWalletModel.Type.MultiCurrency( - cardsInWallet = (scanResponse.card.backupStatus as? CardDTO.BackupStatus.Active) - ?.cardCount?.inc() - ?: 1, - tokensCount = (prevType as? UserWalletModel.Type.MultiCurrency)?.tokensCount ?: 0, - ) - } else { - UserWalletModel.Type.SingleCurrency( - blockchainName = scanResponse.cardTypesResolver.getBlockchain().fullName, - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorState.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorState.kt deleted file mode 100644 index 49e1f753a3..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorState.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.tangem.tap.features.walletSelector.redux - -import com.tangem.common.core.TangemError -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.tap.common.entities.FiatCurrency -import org.rekotlin.StateType - -data class WalletSelectorState( - val wallets: List = emptyList(), - val selectedWalletId: UserWalletId? = null, - val isLocked: Boolean = false, - val fiatCurrency: FiatCurrency = FiatCurrency.Default, - val isCardSavingInProgress: Boolean = false, - val isUnlockInProgress: Boolean = false, - val error: TangemError? = null, -) : StateType \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt deleted file mode 100644 index d01e48d352..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui - -import com.tangem.tap.common.entities.FiatCurrency -import com.tangem.tap.common.extensions.toFormattedFiatValue -import com.tangem.tap.domain.model.TotalFiatBalance -import com.tangem.tap.features.walletSelector.redux.UserWalletModel -import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem -import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem -import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem - -internal fun List.toUiModels(appCurrency: FiatCurrency): Sequence { - return this.asSequence().map { userWalletModel -> - with(userWalletModel) { - val balance = when (fiatBalance) { - is TotalFiatBalance.Failed -> UserWalletItem.Balance.Failed - is TotalFiatBalance.Loading -> UserWalletItem.Balance.Loading - is TotalFiatBalance.Loaded -> UserWalletItem.Balance.Loaded( - amount = fiatBalance.amount.toFormattedFiatValue(appCurrency.symbol, appCurrency.code), - showWarning = fiatBalance.isWarning, - ) - } - when (type) { - is UserWalletModel.Type.MultiCurrency -> MultiCurrencyUserWalletItem( - id = id, - name = name, - imageUrl = artworkUrl, - balance = balance, - isLocked = isLocked, - cardsInWallet = type.cardsInWallet, - tokensCount = type.tokensCount, - ) - is UserWalletModel.Type.SingleCurrency -> SingleCurrencyUserWalletItem( - id = id, - name = name, - imageUrl = artworkUrl, - balance = balance, - isLocked = isLocked, - tokenName = type.blockchainName, - ) - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt deleted file mode 100644 index 2e80036cd4..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt +++ /dev/null @@ -1,100 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui - -import android.app.Dialog -import android.os.Bundle -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material.SnackbarHost -import androidx.compose.material.SnackbarHostState -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.rememberNestedScrollInteropConnection -import androidx.fragment.app.viewModels -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.tangem.core.analytics.Analytics -import com.tangem.core.ui.components.wallets.RenameWalletDialogContent -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.screen.ComposeBottomSheetFragment -import com.tangem.core.ui.theme.AppThemeModeHolder -import com.tangem.tap.common.analytics.events.MyWallets -import com.tangem.tap.features.details.ui.cardsettings.resolveReference -import com.tangem.tap.features.walletSelector.ui.components.* -import com.tangem.tap.features.walletSelector.ui.model.DialogModel -import com.tangem.tap.features.walletSelector.ui.model.WarningModel -import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject - -@AndroidEntryPoint -internal class WalletSelectorBottomSheetFragment : ComposeBottomSheetFragment() { - - @Inject - override lateinit var appThemeModeHolder: AppThemeModeHolder - - private val viewModel by viewModels() - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - Analytics.send(MyWallets.MyWalletsScreenOpened()) - - return super.onCreateDialog(savedInstanceState) - } - - @Composable - override fun ScreenContent(modifier: Modifier) { - val state by viewModel.state.collectAsStateWithLifecycle() - val snackbarHostState = remember { SnackbarHostState() } - val errorMessage by rememberUpdatedState(newValue = state.error?.resolveReference()) - val dialog by rememberUpdatedState(newValue = state.dialog) - - Box(modifier = modifier.nestedScroll(rememberNestedScrollInteropConnection())) { - WalletSelectorScreenContent( - state = state, - onWalletClick = viewModel::walletClicked, - onWalletLongClick = viewModel::walletLongClicked, - onUnlockClick = viewModel::unlock, - onAddCardClick = viewModel::addWallet, - onClearSelectedClick = viewModel::cancelWalletsEditing, - onEditSelectedWalletClick = viewModel::renameWallet, - onDeleteSelectedWalletsClick = viewModel::deleteWallets, - ) - - SnackbarHost( - modifier = Modifier - .align(Alignment.BottomCenter) - .padding(vertical = TangemTheme.dimens.spacing16) - .fillMaxWidth(), - hostState = snackbarHostState, - ) - } - - Dialog(dialog = dialog) - - LaunchedEffect(key1 = errorMessage) { - errorMessage?.let { - snackbarHostState.showSnackbar(it) - viewModel.closeError() - } - } - } - - @Suppress("TopLevelComposableFunctions") - @Composable - private fun Dialog(dialog: DialogModel?) { - if (dialog == null) return - when (dialog) { - is DialogModel.RemoveWalletDialog -> RemoveWalletDialogContent(dialog) - is DialogModel.RenameWalletDialog -> { - RenameWalletDialogContent( - name = dialog.currentName, - onConfirm = dialog.onConfirm, - onDismiss = dialog.onDismiss, - ) - } - is WarningModel.BiometricsLockoutWarning -> BiometricsLockoutWarningContent(dialog) - is WarningModel.KeyInvalidatedWarning -> KeyInvalidatedWarningContent(dialog) - is WarningModel.BiometricsDisabledWarning -> BiometricsDisabledWarningContent(dialog) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorScreenState.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorScreenState.kt deleted file mode 100644 index 796c2eac3f..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorScreenState.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui - -import androidx.compose.runtime.Immutable -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.tap.features.details.ui.cardsettings.TextReference -import com.tangem.tap.features.walletSelector.ui.model.DialogModel -import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem -import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem - -@Immutable -internal data class WalletSelectorScreenState( - val multiCurrencyWallets: List = emptyList(), - val singleCurrencyWallets: List = emptyList(), - val selectedUserWalletId: UserWalletId? = null, - val isLocked: Boolean = false, - val editingUserWalletsIds: List = listOf(), - val dialog: DialogModel? = null, - val showAddCardProgress: Boolean = false, - val showUnlockProgress: Boolean = false, - val error: TextReference? = null, -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt deleted file mode 100644 index 7a83d7bbd4..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt +++ /dev/null @@ -1,278 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.tangem.common.core.TangemError -import com.tangem.core.analytics.Analytics -import com.tangem.domain.wallets.legacy.UserWalletsListError -import com.tangem.domain.wallets.legacy.isLocked -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.tap.common.analytics.events.MyWallets -import com.tangem.tap.common.extensions.dispatchOnMain -import com.tangem.tap.features.details.ui.cardsettings.TextReference -import com.tangem.tap.features.walletSelector.redux.WalletSelectorAction -import com.tangem.tap.features.walletSelector.redux.WalletSelectorState -import com.tangem.tap.features.walletSelector.ui.model.DialogModel -import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem -import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem -import com.tangem.tap.features.walletSelector.ui.model.WarningModel -import com.tangem.tap.store -import com.tangem.tap.userWalletsListManager -import com.tangem.tap.walletStoresManager -import kotlinx.coroutines.flow.* -import org.rekotlin.StoreSubscriber - -internal class WalletSelectorViewModel : ViewModel(), StoreSubscriber { - private val stateInternal = MutableStateFlow(WalletSelectorScreenState()) - val state: StateFlow = stateInternal - - init { - subscribeToStoreChanges() - bootstrapWalletListChanges() - bootstrapWalletsStoresChanges() - bootstrapAppFiatCurrency() - } - - fun unlock() { - store.dispatch(WalletSelectorAction.UnlockWithBiometry) - } - - fun addWallet() { - store.dispatch(WalletSelectorAction.AddWallet) - } - - fun walletClicked(userWalletId: UserWalletId) = with(state.value) { - when { - editingUserWalletsIds.isNotEmpty() && !editingUserWalletsIds.contains(userWalletId) -> { - editWallet(userWalletId) - } - editingUserWalletsIds.isNotEmpty() && editingUserWalletsIds.contains(userWalletId) -> { - cancelWalletEditing(userWalletId) - } - selectedUserWalletId != userWalletId -> { - store.dispatch( - WalletSelectorAction.SelectWallet( - userWalletId = userWalletId, - sendAnalyticsEvent = true, - ), - ) - } - } - } - - fun walletLongClicked(userWalletId: UserWalletId) = with(state.value) { - if (editingUserWalletsIds.isEmpty()) { - editWallet(userWalletId) - } - } - - fun cancelWalletsEditing() { - stateInternal.update { prevState -> - prevState.copy( - editingUserWalletsIds = emptyList(), - ) - } - } - - fun renameWallet() = with(state.value) { - if (editingUserWalletsIds.isNotEmpty() && dialog == null) { - val editedUserWalletId = editingUserWalletsIds.first() - val editedUserWallet = (multiCurrencyWallets + singleCurrencyWallets) - .find { it.id == editedUserWalletId } - - if (editedUserWallet != null) { - Analytics.send(MyWallets.Button.EditWalletTapped()) - val dialog = DialogModel.RenameWalletDialog( - currentName = editedUserWallet.name, - onConfirm = { newName -> - store.dispatch(WalletSelectorAction.RenameWallet(editedUserWalletId, newName)) - stateInternal.update { prevState -> - prevState.copy( - dialog = null, - editingUserWalletsIds = emptyList(), - ) - } - }, - onDismiss = { - stateInternal.update { prevState -> - prevState.copy( - dialog = null, - ) - } - }, - ) - - stateInternal.update { prevState -> - prevState.copy( - dialog = dialog, - ) - } - } - } - } - - fun deleteWallets() = with(state.value) { - if (editingUserWalletsIds.isNotEmpty()) { - val dialog = DialogModel.RemoveWalletDialog( - onConfirm = { - store.dispatch(WalletSelectorAction.RemoveWallets(editingUserWalletsIds)) - stateInternal.update { prevState -> - prevState.copy( - dialog = null, - editingUserWalletsIds = emptyList(), - ) - } - }, - onDismiss = { - stateInternal.update { prevState -> - prevState.copy( - dialog = null, - ) - } - }, - ) - - stateInternal.update { prevState -> - prevState.copy( - dialog = dialog, - ) - } - } - } - - fun closeError() { - store.dispatch(WalletSelectorAction.CloseError) - } - - // TODO: Refactor errors handling - override fun newState(state: WalletSelectorState) { - stateInternal.update { prevState -> - val walletsUi = state.wallets.toUiModels(state.fiatCurrency) - val walletsIds = walletsUi.map { it.id } - val multiCurrencyWallets = arrayListOf() - val singleCurrencyWallets = arrayListOf() - walletsUi.forEach { wallet -> - when (wallet) { - is MultiCurrencyUserWalletItem -> { - multiCurrencyWallets.add(wallet) - } - is SingleCurrencyUserWalletItem -> { - singleCurrencyWallets.add(wallet) - } - } - } - val warningDialog = createWarningDialogIfNeeded(state.error, prevState.dialog) - - prevState.copy( - multiCurrencyWallets = multiCurrencyWallets, - singleCurrencyWallets = singleCurrencyWallets, - selectedUserWalletId = state.selectedWalletId, - editingUserWalletsIds = prevState.editingUserWalletsIds.filter { it in walletsIds }, - isLocked = state.isLocked, - showUnlockProgress = state.isUnlockInProgress, - showAddCardProgress = state.isCardSavingInProgress, - dialog = warningDialog, - error = state.error - ?.takeIf { !it.silent && warningDialog == null } - ?.let { error -> - error.messageResId?.let { TextReference.Res(it) } - ?: TextReference.Str(error.customMessage) - }, - ) - } - } - - override fun onCleared() { - store.unsubscribe(this) - } - - private fun createWarningDialogIfNeeded(error: TangemError?, currentDialog: DialogModel?): DialogModel? { - return when (error) { - is UserWalletsListError.BiometricsAuthenticationLockout -> WarningModel.BiometricsLockoutWarning( - isPermanent = error.isPermanent, - onDismiss = this::dismissWarningDialog, - ) - is UserWalletsListError.AllKeysInvalidated, - is UserWalletsListError.NoUserWalletSelected, - -> WarningModel.KeyInvalidatedWarning( - onDismiss = this::dismissWarningDialog, - ) - is UserWalletsListError.BiometricsAuthenticationDisabled -> WarningModel.BiometricsDisabledWarning( - onDismiss = this::clearUserWallets, - ) - else -> currentDialog - } - } - - private fun clearUserWallets() { - store.dispatch(WalletSelectorAction.ClearUserWallets) - } - - private fun dismissWarningDialog() { - stateInternal.update { prevState -> - prevState.copy( - dialog = null, - ) - } - closeError() - } - - private fun editWallet(userWalletId: UserWalletId) { - stateInternal.update { prevState -> - prevState.copy( - editingUserWalletsIds = prevState.editingUserWalletsIds + userWalletId, - ) - } - } - - private fun cancelWalletEditing(userWalletId: UserWalletId) { - stateInternal.update { prevState -> - prevState.copy( - editingUserWalletsIds = prevState.editingUserWalletsIds - userWalletId, - ) - } - } - - private fun subscribeToStoreChanges() { - store.subscribe(this) { appState -> - appState.skip { old, new -> old.walletSelectorState == new.walletSelectorState } - .select { it.walletSelectorState } - } - } - - private fun bootstrapWalletListChanges() { - userWalletsListManager.userWallets - .onEach { - store.dispatchOnMain(WalletSelectorAction.UserWalletsLoaded(userWallets = it)) - } - .launchIn(viewModelScope) - - userWalletsListManager.selectedUserWallet - .onEach { - store.dispatchOnMain(WalletSelectorAction.SelectedWalletChanged(selectedWallet = it)) - } - .launchIn(viewModelScope) - - userWalletsListManager.isLocked - .onEach { - store.dispatchOnMain(WalletSelectorAction.IsLockedChanged(isLocked = it)) - } - .launchIn(viewModelScope) - } - - private fun bootstrapWalletsStoresChanges() { - walletStoresManager.getAll() - .onEach { walletStores -> - store.dispatchOnMain(WalletSelectorAction.WalletStoresChanged(walletStores)) - } - .launchIn(viewModelScope) - } - - private fun bootstrapAppFiatCurrency() { - store.dispatch( - WalletSelectorAction.ChangeAppCurrency( - fiatCurrency = store.state.globalState.appCurrency, - ), - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/BiometricsDisabledWarningContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/BiometricsDisabledWarningContent.kt deleted file mode 100644 index 61e8bd9000..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/BiometricsDisabledWarningContent.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui.components - -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.BasicDialog -import com.tangem.core.ui.components.DialogButton -import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.walletSelector.ui.model.WarningModel -import com.tangem.wallet.R - -@Composable -internal fun BiometricsDisabledWarningContent(warning: WarningModel.BiometricsDisabledWarning) { - BasicDialog( - title = stringResource(id = R.string.common_warning), - message = stringResource(id = R.string.biometric_unavailable_warning), - onDismissDialog = warning.onDismiss, - isDismissable = false, - confirmButton = DialogButton( - title = stringResource(id = R.string.common_ok), - onClick = warning.onDismiss, - ), - ) -} - -// region Preview -@Composable -private fun BiometricsDisabledWarningContentSample(modifier: Modifier = Modifier) { - Column(modifier = modifier) { - BiometricsDisabledWarningContent( - warning = WarningModel.BiometricsDisabledWarning( - onDismiss = {}, - ), - ) - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun BiometricsDisabledWarningContentPreview_Light() { - TangemTheme { - BiometricsDisabledWarningContentSample() - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun BiometricsDisabledWarningContentPreview_Dark() { - TangemTheme(isDark = true) { - BiometricsDisabledWarningContentSample() - } -} -// endregion Preview \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/BiometricsLockoutWarningContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/BiometricsLockoutWarningContent.kt deleted file mode 100644 index 3abfb1ade2..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/BiometricsLockoutWarningContent.kt +++ /dev/null @@ -1,89 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui.components - -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.BasicDialog -import com.tangem.core.ui.components.DialogButton -import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.walletSelector.ui.model.WarningModel -import com.tangem.wallet.R - -@Composable -internal fun BiometricsLockoutWarningContent(warning: WarningModel.BiometricsLockoutWarning) { - BasicDialog( - title = stringResource(id = R.string.biometric_lockout_warning_title), - message = stringResource( - id = if (warning.isPermanent) { - R.string.biometric_lockout_permanent_warning_description - } else { - R.string.biometric_lockout_warning_description - }, - ), - onDismissDialog = warning.onDismiss, - confirmButton = DialogButton( - title = stringResource(id = R.string.common_ok), - onClick = warning.onDismiss, - ), - ) -} - -// region Preview -@Composable -private fun BiometricsLockoutDialogSample(modifier: Modifier = Modifier) { - Column(modifier = modifier) { - BiometricsLockoutWarningContent( - warning = WarningModel.BiometricsLockoutWarning( - isPermanent = false, - onDismiss = {}, - ), - ) - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun BiometricsLockoutDialogPreview_Light() { - TangemTheme { - BiometricsLockoutDialogSample() - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun BiometricsLockoutDialogPreview_Dark() { - TangemTheme(isDark = true) { - BiometricsLockoutDialogSample() - } -} - -@Composable -private fun BiometricsLockoutDialog_Permanent_Sample(modifier: Modifier = Modifier) { - Column(modifier = modifier) { - BiometricsLockoutWarningContent( - warning = WarningModel.BiometricsLockoutWarning( - isPermanent = true, - onDismiss = {}, - ), - ) - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun BiometricsLockoutDialog_Permanent_Preview_Light() { - TangemTheme { - BiometricsLockoutDialog_Permanent_Sample() - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun BiometricsLockoutDialog_Permanent_Preview_Dark() { - TangemTheme(isDark = true) { - BiometricsLockoutDialog_Permanent_Sample() - } -} -// endregion Preview \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/KeyInvalidatedWarningContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/KeyInvalidatedWarningContent.kt deleted file mode 100644 index 4459f55a1d..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/KeyInvalidatedWarningContent.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui.components - -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.BasicDialog -import com.tangem.core.ui.components.DialogButton -import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.walletSelector.ui.model.WarningModel -import com.tangem.wallet.R - -@Composable -internal fun KeyInvalidatedWarningContent(warning: WarningModel.KeyInvalidatedWarning) { - BasicDialog( - title = stringResource(id = R.string.common_attention), - message = stringResource(id = R.string.key_invalidated_warning_description), - onDismissDialog = warning.onDismiss, - confirmButton = DialogButton( - title = stringResource(id = R.string.common_ok), - onClick = warning.onDismiss, - ), - ) -} - -// region Preview -@Composable -private fun KeyInvalidatedWarningSample(modifier: Modifier = Modifier) { - Column(modifier = modifier) { - KeyInvalidatedWarningContent( - warning = WarningModel.KeyInvalidatedWarning(onDismiss = {}), - ) - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun KeyInvalidatedWarningPreview_Light() { - TangemTheme { - KeyInvalidatedWarningSample() - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun KeyInvalidatedWarningPreview_Dark() { - TangemTheme(isDark = true) { - KeyInvalidatedWarningSample() - } -} -// endregion Preview \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt deleted file mode 100644 index 0099f47c84..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui.components - -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.tap.features.walletSelector.ui.WalletSelectorScreenState -import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem -import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem -import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem - -internal object MockData { - private val multiCurrencyUserWallet = MultiCurrencyUserWalletItem( - id = UserWalletId("wallet_1"), - balance = UserWalletItem.Balance.Loaded( - amount = "6781.05 $", - showWarning = true, - ), - name = "Wallet", - imageUrl = "https://app.tangem.com/cards/card_default.png", - isLocked = false, - tokensCount = 12, - cardsInWallet = 3, - ) - - private val singleCurrencyUserWallet = SingleCurrencyUserWalletItem( - id = UserWalletId("wallet_4"), - balance = UserWalletItem.Balance.Loaded( - amount = "6781.05 $", - showWarning = false, - ), - name = "Wallet", - imageUrl = "https://app.tangem.com/cards/card_default.png", - isLocked = false, - tokenName = "Ethereum", - ) - - val state = WalletSelectorScreenState( - multiCurrencyWallets = listOf( - multiCurrencyUserWallet, - multiCurrencyUserWallet.copy(id = UserWalletId("wallet_2")), - multiCurrencyUserWallet.copy(id = UserWalletId("wallet_3"), tokensCount = 2, cardsInWallet = 1), - ), - singleCurrencyWallets = listOf(singleCurrencyUserWallet), - selectedUserWalletId = multiCurrencyUserWallet.id, - isLocked = false, - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/RemoveWalletDialogContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/RemoveWalletDialogContent.kt deleted file mode 100644 index cedbb48278..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/RemoveWalletDialogContent.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui.components - -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import com.tangem.core.ui.components.BasicDialog -import com.tangem.core.ui.components.DialogButton -import com.tangem.tap.features.walletSelector.ui.model.DialogModel -import com.tangem.wallet.R - -@Composable -internal fun RemoveWalletDialogContent(dialog: DialogModel.RemoveWalletDialog) { - BasicDialog( - message = stringResource(id = R.string.user_wallet_list_delete_prompt), - confirmButton = DialogButton( - title = stringResource(id = R.string.common_delete), - warning = true, - onClick = dialog.onConfirm, - ), - dismissButton = DialogButton( - onClick = dialog.onDismiss, - ), - onDismissDialog = dialog.onDismiss, - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt deleted file mode 100644 index 0993a1c9ea..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt +++ /dev/null @@ -1,330 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui.components - -import androidx.annotation.StringRes -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberUpdatedState -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.PrimaryButton -import com.tangem.core.ui.components.SecondaryButtonIconEnd -import com.tangem.core.ui.components.SpacerWMax -import com.tangem.core.ui.components.atoms.Hand -import com.tangem.core.ui.res.TangemTheme -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.tap.features.walletSelector.ui.WalletSelectorScreenState -import com.tangem.wallet.R - -@Suppress("LongParameterList") -@OptIn(ExperimentalFoundationApi::class) -@Composable -internal fun WalletSelectorScreenContent( - state: WalletSelectorScreenState, - onWalletClick: (UserWalletId) -> Unit, - onWalletLongClick: (UserWalletId) -> Unit, - onUnlockClick: () -> Unit, - onAddCardClick: () -> Unit, - onClearSelectedClick: () -> Unit, - onEditSelectedWalletClick: () -> Unit, - onDeleteSelectedWalletsClick: () -> Unit, -) { - LazyColumn { - stickyHeader { - Header( - editingWalletsIds = state.editingUserWalletsIds, - onClearSelectedClick = onClearSelectedClick, - onEditSelectedWalletClick = onEditSelectedWalletClick, - onDeleteSelectedWalletsClick = onDeleteSelectedWalletsClick, - ) - } - - item { - WalletsTitle(textResId = R.string.user_wallet_list_multi_header, wallets = state.multiCurrencyWallets) - } - - itemsIndexed( - items = state.multiCurrencyWallets, - key = { _, wallet -> wallet.id.stringValue }, - ) { _, wallet -> - - WalletItem( - wallet = wallet, - isSelected = remember(state.selectedUserWalletId) { wallet.id == state.selectedUserWalletId }, - isChecked = remember(state.editingUserWalletsIds) { wallet.id in state.editingUserWalletsIds }, - onWalletClick = { onWalletClick(wallet.id) }, - onWalletLongClick = { onWalletLongClick(wallet.id) }, - ) - } - - item { - WalletsTitle(textResId = R.string.user_wallet_list_single_header, wallets = state.singleCurrencyWallets) - } - - itemsIndexed( - items = state.singleCurrencyWallets, - key = { _, wallet -> wallet.id.stringValue }, - ) { _, wallet -> - WalletItem( - wallet = wallet, - isSelected = remember(state.selectedUserWalletId) { wallet.id == state.selectedUserWalletId }, - isChecked = remember(state.editingUserWalletsIds) { wallet.id in state.editingUserWalletsIds }, - onWalletClick = { onWalletClick(wallet.id) }, - onWalletLongClick = { onWalletLongClick(wallet.id) }, - ) - } - - item { - Footer( - isLocked = state.isLocked, - showUnlockProgress = state.showUnlockProgress, - showAddCardProgress = state.showAddCardProgress, - onUnlockClick = onUnlockClick, - onAddCardClick = onAddCardClick, - ) - } - } -} - -@Composable -private fun Header( - editingWalletsIds: List, - onClearSelectedClick: () -> Unit, - onEditSelectedWalletClick: () -> Unit, - onDeleteSelectedWalletsClick: () -> Unit, -) { - val editingWalletsSize by rememberUpdatedState(newValue = editingWalletsIds.size) - val hasEditingWallets by remember { derivedStateOf { editingWalletsSize > 0 } } - - Column( - modifier = Modifier - .fillMaxWidth() - .background( - color = TangemTheme.colors.background.plain, - shape = TangemTheme.shapes.bottomSheet, - ), - ) { - Hand() - Box( - modifier = Modifier - .fillMaxWidth() - .height(TangemTheme.dimens.size44), - contentAlignment = Alignment.Center, - ) { - if (hasEditingWallets) { - EditWalletsBar( - editingWalletsSize = editingWalletsSize, - onClearSelectedClick = onClearSelectedClick, - onEditSelectedWalletClick = onEditSelectedWalletClick, - onDeleteSelectedWalletsClick = onDeleteSelectedWalletsClick, - ) - } else { - Text( - text = stringResource(R.string.user_wallet_list_title), - style = TangemTheme.typography.subtitle1, - color = TangemTheme.colors.text.primary1, - textAlign = TextAlign.Center, - ) - } - } - } -} - -@Composable -private fun WalletsTitle(@StringRes textResId: Int, wallets: List<*>) { - if (wallets.isNotEmpty()) { - Text( - modifier = Modifier.padding(start = TangemTheme.dimens.spacing16), - text = stringResource(id = textResId), - style = TangemTheme.typography.subtitle2, - color = TangemTheme.colors.text.tertiary, - ) - } -} - -@Composable -private fun Footer( - isLocked: Boolean, - showUnlockProgress: Boolean, - showAddCardProgress: Boolean, - onUnlockClick: () -> Unit, - onAddCardClick: () -> Unit, -) { - Column( - modifier = Modifier - .padding( - top = TangemTheme.dimens.spacing24, - bottom = TangemTheme.dimens.spacing16, - ) - .padding(horizontal = TangemTheme.dimens.spacing16) - .fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), - ) { - if (isLocked) { - PrimaryButton( - modifier = Modifier.fillMaxWidth(), - text = stringResource( - id = R.string.user_wallet_list_unlock_all_with, - stringResource(id = R.string.common_biometrics), - ), - showProgress = showUnlockProgress, - onClick = onUnlockClick, - ) - } - SecondaryButtonIconEnd( - modifier = Modifier.fillMaxWidth(), - text = stringResource(R.string.user_wallet_list_add_button), - showProgress = showAddCardProgress, - iconResId = R.drawable.ic_tangem_24, - onClick = onAddCardClick, - ) - } -} - -@Composable -private fun EditWalletsBar( - editingWalletsSize: Int, - onClearSelectedClick: () -> Unit, - onEditSelectedWalletClick: () -> Unit, - onDeleteSelectedWalletsClick: () -> Unit, -) { - val showEditAction by remember(editingWalletsSize) { - derivedStateOf { editingWalletsSize in 1 until 2 } - } - - Row( - modifier = Modifier - .padding(horizontal = TangemTheme.dimens.spacing16) - .fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), - ) { - IconButton( - modifier = Modifier.size(TangemTheme.dimens.size32), - onClick = onClearSelectedClick, - ) { - Icon( - modifier = Modifier.size(TangemTheme.dimens.size24), - painter = painterResource(id = R.drawable.ic_close_24), - tint = TangemTheme.colors.icon.primary1, - contentDescription = "Unselect wallets", - ) - } - Text( - text = stringResource(id = R.string.user_wallet_list_editing_count, editingWalletsSize), - style = TangemTheme.typography.subtitle1, - color = TangemTheme.colors.text.primary1, - ) - SpacerWMax() - if (showEditAction) { - IconButton( - modifier = Modifier.size(TangemTheme.dimens.size32), - onClick = onEditSelectedWalletClick, - ) { - Icon( - modifier = Modifier.size(TangemTheme.dimens.size24), - painter = painterResource(id = R.drawable.ic_pencil_outline_24), - tint = TangemTheme.colors.icon.primary1, - contentDescription = "Change wallet name", - ) - } - } - IconButton( - modifier = Modifier.size(TangemTheme.dimens.size32), - onClick = onDeleteSelectedWalletsClick, - ) { - Icon( - modifier = Modifier.size(TangemTheme.dimens.size24), - painter = painterResource(id = R.drawable.ic_trash), - tint = TangemTheme.colors.icon.warning, - contentDescription = "Delete selected wallets", - ) - } - } -} - -// region Preview -@Composable -private fun WalletSelectorScreenContentSample(modifier: Modifier = Modifier) { - Column( - modifier = modifier - .background(color = TangemTheme.colors.background.primary), - ) { - WalletSelectorScreenContent( - state = MockData.state.copy(isLocked = true), - onWalletClick = { /* no-op */ }, - onWalletLongClick = { /* no-op */ }, - onUnlockClick = { /* no-op */ }, - onAddCardClick = { /* no-op */ }, - onEditSelectedWalletClick = { /* no-op */ }, - onClearSelectedClick = { /* no-op */ }, - onDeleteSelectedWalletsClick = { /* no-op */ }, - ) - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun WalletSelectorScreenContentPreview_Light() { - TangemTheme { - WalletSelectorScreenContentSample() - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun WalletSelectorScreenContentPreview_Dark() { - TangemTheme(isDark = true) { - WalletSelectorScreenContentSample() - } -} - -@Composable -private fun WalletSelectorScreenContent_EditWallets_Sample(modifier: Modifier = Modifier) { - Column( - modifier = modifier - .background(TangemTheme.colors.background.primary), - ) { - WalletSelectorScreenContent( - state = MockData.state - .copy(editingUserWalletsIds = listOf(MockData.state.multiCurrencyWallets[2].id)), - onWalletClick = { /* no-op */ }, - onWalletLongClick = { /* no-op */ }, - onUnlockClick = { /* no-op */ }, - onAddCardClick = { /* no-op */ }, - onEditSelectedWalletClick = { /* no-op */ }, - onClearSelectedClick = { /* no-op */ }, - onDeleteSelectedWalletsClick = { /* no-op */ }, - ) - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun WalletSelectorScreenContent_EditWallets_Preview_Light() { - TangemTheme { - WalletSelectorScreenContent_EditWallets_Sample() - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun WalletSelectorScreenContent_EditWallets_Preview_Dark() { - TangemTheme(isDark = true) { - WalletSelectorScreenContent_EditWallets_Sample() - } -} -// endregion Preview \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt deleted file mode 100644 index 0224ee04fc..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt +++ /dev/null @@ -1,459 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui.components - -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.combinedClickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.Divider -import androidx.compose.material.Icon -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.BlendMode -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.pluralStringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import coil.compose.SubcomposeAsyncImage -import coil.request.ImageRequest -import com.tangem.core.ui.components.SpacerH2 -import com.tangem.core.ui.components.SpacerW6 -import com.tangem.core.ui.components.SpacerW8 -import com.tangem.core.ui.res.TangemTheme -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.tap.common.extensions.cardImageData -import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem -import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem -import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem -import com.tangem.wallet.R -import com.valentinilk.shimmer.shimmer - -@OptIn(ExperimentalFoundationApi::class) -@Composable -internal fun WalletItem( - wallet: UserWalletItem, - isSelected: Boolean, - isChecked: Boolean, - onWalletClick: () -> Unit, - onWalletLongClick: () -> Unit, -) { - Row( - modifier = Modifier - .combinedClickable( - onClick = onWalletClick, - onLongClick = onWalletLongClick, - ) - .heightIn(min = TangemTheme.dimens.size72) - .padding(all = TangemTheme.dimens.spacing16), - verticalAlignment = Alignment.CenterVertically, - ) { - WalletCardImage( - cardImageUrl = wallet.imageUrl, - isChecked = isChecked, - isSelected = isSelected, - ) - SpacerW8() - WalletInfo(wallet = wallet, isSelected = isSelected) - SpacerW6() - TokensInfo( - isLocked = wallet.isLocked, - balance = wallet.balance, - tokensCount = (wallet as? MultiCurrencyUserWalletItem)?.tokensCount, - ) - } -} - -@Composable -private fun WalletCardImage(cardImageUrl: String, isChecked: Boolean, isSelected: Boolean) { - Box( - modifier = Modifier - .width(TangemTheme.dimens.size62) - .height(TangemTheme.dimens.size42), - ) { - val cardImageModifier = Modifier - .align(Alignment.Center) - .width(TangemTheme.dimens.size56) - .height(TangemTheme.dimens.size32) - .clip(TangemTheme.shapes.roundedCornersSmall2) - - val tintColor = TangemTheme.colors.icon.accent.copy(alpha = .6f) - val checkedColorFilter = remember(isChecked) { - if (isChecked) { - ColorFilter.tint( - color = tintColor, - blendMode = BlendMode.SrcOver, - ) - } else { - null - } - } - - SubcomposeAsyncImage( - modifier = cardImageModifier, - model = ImageRequest.Builder(LocalContext.current) - .cardImageData(cardImageUrl) - .crossfade(true) - .build(), - loading = { CardImageShimmer(modifier = cardImageModifier) }, - error = { CardImagePlaceholder(modifier = cardImageModifier) }, - colorFilter = checkedColorFilter, - contentDescription = null, - ) - - when { - isChecked -> { - CheckedWalletMark( - modifier = Modifier.matchParentSize(), - ) - } - isSelected -> { - SelectedWalletBadge( - modifier = Modifier.align(Alignment.TopEnd), - ) - } - } - } -} - -@Composable -private fun RowScope.WalletInfo(wallet: UserWalletItem, isSelected: Boolean) { - Column( - modifier = Modifier.weight(weight = 2f), - verticalArrangement = Arrangement.SpaceAround, - horizontalAlignment = Alignment.Start, - ) { - Text( - text = wallet.name, - color = if (isSelected) TangemTheme.colors.text.accent else TangemTheme.colors.text.primary1, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - style = TangemTheme.typography.subtitle1, - ) - SpacerH2() - Text( - text = when (wallet) { - is MultiCurrencyUserWalletItem -> pluralStringResource( - id = R.plurals.card_label_card_count, - count = wallet.cardsInWallet, - wallet.cardsInWallet, - ) - is SingleCurrencyUserWalletItem -> wallet.tokenName - }, - color = TangemTheme.colors.text.tertiary, - maxLines = 1, - style = TangemTheme.typography.caption2, - ) - } -} - -@Composable -private fun RowScope.TokensInfo(isLocked: Boolean, balance: UserWalletItem.Balance, tokensCount: Int?) { - Column( - modifier = Modifier.weight(weight = 3f), - verticalArrangement = Arrangement.SpaceAround, - horizontalAlignment = Alignment.End, - ) { - if (isLocked) { - LockedPlaceholder() - } else { - when (balance) { - is UserWalletItem.Balance.Failed, - is UserWalletItem.Balance.Loaded, - -> { - LoadedTokensInfo( - balanceAmount = balance.amount, - tokensCount = tokensCount, - showWarning = balance.showWarning, - ) - } - is UserWalletItem.Balance.Loading -> { - LoadingTokensInfo(isMultiCurrencyWallet = tokensCount != null) - } - } - } - } -} - -@Composable -private fun LoadingTokensInfo(isMultiCurrencyWallet: Boolean) { - Column( - modifier = Modifier.shimmer(), - horizontalAlignment = Alignment.End, - verticalArrangement = Arrangement.SpaceAround, - ) { - Box( - modifier = Modifier - .width(TangemTheme.dimens.size62) - .height(TangemTheme.dimens.size16) - .background( - color = TangemTheme.colors.button.secondary, - shape = TangemTheme.shapes.roundedCornersSmall2, - ), - ) - if (isMultiCurrencyWallet) { - SpacerH2() - Box( - modifier = Modifier - .width(TangemTheme.dimens.size48) - .height(TangemTheme.dimens.size12) - .background( - color = TangemTheme.colors.button.secondary, - shape = TangemTheme.shapes.roundedCornersSmall2, - ), - ) - } - } -} - -@Composable -private fun LoadedTokensInfo( - balanceAmount: String, - tokensCount: Int?, - showWarning: Boolean, - modifier: Modifier = Modifier, -) { - Column( - modifier = modifier, - horizontalAlignment = Alignment.End, - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4), - ) { - Text( - text = balanceAmount, - color = TangemTheme.colors.text.primary1, - textAlign = TextAlign.End, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - style = TangemTheme.typography.subtitle1, - ) - if (showWarning) { - Icon( - modifier = Modifier.size(TangemTheme.dimens.size16), - painter = painterResource(id = R.drawable.ic_alert_24), - tint = TangemTheme.colors.icon.attention, - contentDescription = null, - ) - } - } - if (tokensCount != null) { - SpacerH2() - Text( - text = pluralStringResource( - id = R.plurals.token_count, - count = tokensCount, - tokensCount, - ), - style = TangemTheme.typography.caption2, - color = TangemTheme.colors.text.tertiary, - textAlign = TextAlign.End, - ) - } - } -} - -@Composable -private fun LockedPlaceholder(modifier: Modifier = Modifier) { - Box( - modifier = modifier - .padding(vertical = TangemTheme.dimens.spacing2) - .background( - color = TangemTheme.colors.button.secondary, - shape = TangemTheme.shapes.roundedCornersMedium, - ), - ) { - Icon( - modifier = Modifier - .padding( - vertical = TangemTheme.dimens.spacing8, - horizontal = TangemTheme.dimens.spacing12, - ) - .size(TangemTheme.dimens.size20), - painter = painterResource(id = R.drawable.ic_locked_24), - tint = TangemTheme.colors.icon.primary1, - contentDescription = null, - ) - } -} - -@Composable -private fun CardImagePlaceholder(modifier: Modifier = Modifier) { - Box(modifier = modifier) { - Image( - modifier = Modifier.matchParentSize(), - painter = painterResource(id = R.drawable.card_placeholder_black), - contentDescription = null, - ) - } -} - -@Composable -private fun CardImageShimmer(modifier: Modifier = Modifier) { - Box(modifier = modifier.shimmer()) { - Box( - modifier = Modifier - .matchParentSize() - .background(TangemTheme.colors.button.secondary), - ) - } -} - -@Composable -private fun SelectedWalletBadge(modifier: Modifier = Modifier) { - Box( - modifier = modifier - .size(TangemTheme.dimens.size18) - .background( - color = Color.White, - shape = CircleShape, - ), - contentAlignment = Alignment.Center, - ) { - Icon( - modifier = Modifier.padding(all = 0.5.dp), - painter = painterResource(id = R.drawable.ic_check_circle_18), - tint = TangemTheme.colors.icon.accent, - contentDescription = null, - ) - } -} - -@Composable -private fun CheckedWalletMark(modifier: Modifier = Modifier) { - Box( - modifier = modifier, - contentAlignment = Alignment.Center, - ) { - Icon( - painter = painterResource(id = R.drawable.ic_check_24), - tint = TangemTheme.colors.icon.primary2, - contentDescription = null, - ) - } -} - -// region Preview -@Composable -@Suppress("LongMethod") // preview -private fun WalletItemSample(modifier: Modifier = Modifier) { - Column( - modifier = modifier - .background(TangemTheme.colors.background.primary), - ) { - WalletItem( - wallet = MultiCurrencyUserWalletItem( - id = UserWalletId(value = null), - name = "Tangem Card", - imageUrl = "", - balance = UserWalletItem.Balance.Loaded( - amount = "1412121218 BTC", - showWarning = false, - ), - isLocked = false, - tokensCount = 2, - cardsInWallet = 1, - ), - isSelected = false, - isChecked = false, - onWalletClick = {}, - onWalletLongClick = {}, - ) - Divider(modifier = Modifier.padding(vertical = 4.dp)) - WalletItem( - wallet = MultiCurrencyUserWalletItem( - id = UserWalletId(value = null), - name = "Tangem Card", - imageUrl = "", - balance = UserWalletItem.Balance.Loaded( - amount = "1412121218 BTC", - showWarning = true, - ), - isLocked = false, - tokensCount = 2, - cardsInWallet = 1, - ), - isSelected = false, - isChecked = false, - onWalletClick = {}, - onWalletLongClick = {}, - ) - Divider(modifier = Modifier.padding(vertical = 4.dp)) - WalletItem( - wallet = MultiCurrencyUserWalletItem( - id = UserWalletId(value = null), - name = "Tangem Card", - imageUrl = "", - balance = UserWalletItem.Balance.Loading, - isLocked = true, - tokensCount = 2, - cardsInWallet = 1, - ), - isSelected = false, - isChecked = false, - onWalletClick = {}, - onWalletLongClick = {}, - ) - Divider(modifier = Modifier.padding(vertical = 4.dp)) - WalletItem( - wallet = MultiCurrencyUserWalletItem( - id = UserWalletId(value = null), - name = "Tangem Card", - imageUrl = "", - balance = UserWalletItem.Balance.Failed, - isLocked = false, - tokensCount = 2, - cardsInWallet = 1, - ), - isSelected = true, - isChecked = false, - onWalletClick = {}, - onWalletLongClick = {}, - ) - Divider(modifier = Modifier.padding(vertical = 4.dp)) - WalletItem( - wallet = SingleCurrencyUserWalletItem( - id = UserWalletId(value = null), - name = "Tangem Card", - imageUrl = "", - balance = UserWalletItem.Balance.Loaded( - amount = "141212121888 BTC", - showWarning = false, - ), - isLocked = false, - tokenName = "Bitcoin", - ), - isSelected = false, - isChecked = true, - onWalletClick = {}, - onWalletLongClick = {}, - ) - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun WalletItemPreview_Light() { - TangemTheme { - WalletItemSample() - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun WalletItemPreview_Dark() { - TangemTheme(isDark = true) { - WalletItemSample() - } -} -// endregion Preview \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/DialogModel.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/DialogModel.kt deleted file mode 100644 index 87039dc113..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/DialogModel.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui.model - -internal sealed interface DialogModel { - data class RenameWalletDialog( - val currentName: String, - val onConfirm: (newName: String) -> Unit, - val onDismiss: () -> Unit, - ) : DialogModel - - data class RemoveWalletDialog( - val onConfirm: () -> Unit, - val onDismiss: () -> Unit, - ) : DialogModel -} - -internal sealed interface WarningModel : DialogModel { - data class BiometricsLockoutWarning( - val isPermanent: Boolean, - val onDismiss: () -> Unit, - ) : WarningModel - - data class KeyInvalidatedWarning( - val onDismiss: () -> Unit, - ) : WarningModel - - data class BiometricsDisabledWarning( - val onDismiss: () -> Unit, - ) : WarningModel -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt deleted file mode 100644 index 546be07f7c..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui.model - -import com.tangem.core.ui.utils.BigDecimalFormatter -import com.tangem.domain.wallets.models.UserWalletId - -internal sealed interface UserWalletItem { - val id: UserWalletId - val name: String - val imageUrl: String - val balance: Balance - val isLocked: Boolean - - sealed class Balance { - open val amount: String = BigDecimalFormatter.EMPTY_BALANCE_SIGN - open val showWarning: Boolean = false - - object Loading : Balance() - - object Failed : Balance() { - override val showWarning: Boolean = true - } - - data class Loaded( - override val amount: String, - override val showWarning: Boolean, - ) : Balance() - } -} - -internal data class MultiCurrencyUserWalletItem( - override val id: UserWalletId, - override val name: String, - override val imageUrl: String, - override val balance: UserWalletItem.Balance, - override val isLocked: Boolean, - val tokensCount: Int, - val cardsInWallet: Int, -) : UserWalletItem - -internal data class SingleCurrencyUserWalletItem( - override val id: UserWalletId, - override val name: String, - override val imageUrl: String, - override val balance: UserWalletItem.Balance, - override val isLocked: Boolean, - val tokenName: String, -) : UserWalletItem \ No newline at end of file diff --git a/core/navigation/src/main/java/com/tangem/core/navigation/NavigationState.kt b/core/navigation/src/main/java/com/tangem/core/navigation/NavigationState.kt index 9f96640d74..63bd6084ce 100644 --- a/core/navigation/src/main/java/com/tangem/core/navigation/NavigationState.kt +++ b/core/navigation/src/main/java/com/tangem/core/navigation/NavigationState.kt @@ -34,7 +34,6 @@ enum class AppScreen(val isDialogFragment: Boolean = false) { Swap, Welcome, SaveWallet(isDialogFragment = true), - WalletSelector(isDialogFragment = true), AppCurrencySelector, ModalNotification(isDialogFragment = true), } \ No newline at end of file