From e2cc040d689d27b6b119742a1b14da1e3e428081 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Jun 2024 13:37:39 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../com/tangem/tap/ApplicationEntryPoint.kt | 3 - .../main/java/com/tangem/tap/MainActivity.kt | 5 - .../java/com/tangem/tap/TangemApplication.kt | 5 - .../tap/proxy/redux/DaggerGraphAction.kt | 2 - .../tap/proxy/redux/DaggerGraphReducer.kt | 1 - .../tap/proxy/redux/DaggerGraphState.kt | 4 - .../configs/feature_toggles_config.json | 4 - features/manage-tokens/.gitignore | 1 - .../ManageTokensFeatureToggles.kt | 5 - .../navigation/ExpandableState.kt | 6 - .../managetokens/navigation/ManageTokensUi.kt | 12 - .../di/ManageTokensFeatureTogglesModule.kt | 21 - .../di/ManageTokensRouterModule.kt | 18 - .../DefaultManageTokensFeatureToggles.kt | 11 - .../router/AddCustomTokenRoute.kt | 14 - .../router/AddCustomTokenRouter.kt | 29 -- .../state/AddCustomTokenState.kt | 18 - .../state/AddCustomTokenWarning.kt | 32 -- .../addcustomtoken/state/ButtonState.kt | 6 - .../state/ChooseDerivationState.kt | 13 - .../state/ChooseNetworkState.kt | 12 - .../addcustomtoken/state/CustomTokenData.kt | 18 - .../addcustomtoken/state/Derivation.kt | 9 - .../state/EnterCustomDerivationState.kt | 10 - .../addcustomtoken/state/TextFieldState.kt | 34 -- .../factory/AddCustomTokenStateFactory.kt | 395 -------------- ...stomTokenStateToCryptoCurrencyConverter.kt | 58 --- ...ntractAddressToCustomTokenDataConverter.kt | 39 -- .../FoundTokenToCustomTokenDataConverter.kt | 40 -- .../NetworkToNetworkItemStateConverter.kt | 20 - .../previewdata/AddCustomTokenPreviewData.kt | 50 -- .../ChooseDerivationPreviewData.kt | 42 -- .../ChooseNetworkCustomPreviewData.kt | 32 -- .../ui/AddCustomTokenBottomSheet.kt | 202 -------- .../addcustomtoken/ui/AddCustomTokenScreen.kt | 298 ----------- .../ui/ChooseDerivationScreen.kt | 109 ---- .../ui/ChooseNetworkCustomScreen.kt | 89 ---- .../ui/CustomDerivationDialog.kt | 43 -- .../ui/CustomTokenChooseWalletScreen.kt | 20 - .../addcustomtoken/ui/TokenTextField.kt | 81 --- .../viewmodels/AddCustomTokenClickIntents.kt | 54 -- .../viewmodels/AddCustomTokenViewModel.kt | 484 ------------------ .../common/analytics/ManageTokens.kt | 102 ---- .../presentation/common/state/AlertState.kt | 56 -- .../common/state/ChooseWalletState.kt | 29 -- .../presentation/common/state/Event.kt | 8 - .../common/state/NetworkItemState.kt | 82 --- .../presentation/common/state/WalletState.kt | 8 - .../ChooseWalletStatePreviewData.kt | 27 - .../common/ui/ChooseWalletBottomSheet.kt | 22 - .../common/ui/ChooseWalletScreen.kt | 150 ------ .../presentation/common/ui/EventEffect.kt | 18 - .../common/ui/components/Alert.kt | 52 -- .../common/ui/components/NetworkItem.kt | 167 ------ .../ui/components/SimpleSelectionBlock.kt | 65 --- .../common/utils/CurrencyUtils.kt | 18 - .../managetokens/state/ChooseNetworkState.kt | 11 - .../state/DerivationNotificationState.kt | 34 -- .../managetokens/state/ManageTokensState.kt | 27 - .../managetokens/state/QuotesState.kt | 14 - .../managetokens/state/SearchBarState.kt | 11 - .../managetokens/state/TokenButtonType.kt | 5 - .../managetokens/state/TokenIconState.kt | 10 - .../managetokens/state/TokenItemState.kt | 23 - .../state/factory/ManageTokensStateFactory.kt | 194 ------- .../NetworkToNetworkItemStateConverter.kt | 57 --- .../NetworksToChooseNetworkStateConverter.kt | 36 -- .../factory/QuotesToQuotesStateConverter.kt | 34 -- .../state/factory/TokenConverter.kt | 67 --- .../factory/TokenToCryptoCurrencyConverter.kt | 37 -- .../ChooseNetworkStatePreviewData.kt | 56 -- .../DerivationNotificationStatePreviewData.kt | 12 - .../ManageTokensStatePreviewData.kt | 45 -- .../previewdata/TokenItemStatePreviewData.kt | 77 --- .../ui/ChooseNetworkBottomSheet.kt | 24 - .../managetokens/ui/ChooseNetworkScreen.kt | 201 -------- .../managetokens/ui/ManageTokensScreen.kt | 197 ------- .../ui/components/AddCustomTokenButton.kt | 60 --- .../ui/components/DerivationNotification.kt | 138 ----- .../ui/components/PriceChangesChart.kt | 134 ----- .../managetokens/ui/components/SearchBar.kt | 138 ----- .../managetokens/ui/components/TokenButton.kt | 85 --- .../managetokens/ui/components/TokenIcon.kt | 121 ----- .../ui/components/TokenPriceChange.kt | 82 --- .../ui/components/TokenRowItem.kt | 203 -------- .../managetokens/ui/components/TokensList.kt | 67 --- .../viewmodels/ManageTokensClickIntents.kt | 31 -- .../viewmodels/ManageTokensUiEvents.kt | 8 - .../viewmodels/ManageTokensViewModel.kt | 445 ---------------- .../presentation/router/ManageTokensUiImpl.kt | 25 - .../wallet/presentation/WalletFragment.kt | 5 - .../common/preview/WalletScreenPreviewData.kt | 4 - .../router/DefaultWalletRouter.kt | 20 +- .../presentation/router/InnerWalletRouter.kt | 4 +- .../wallet/state/WalletStateController.kt | 9 +- .../wallet/state/model/WalletScreenState.kt | 4 - .../presentation/wallet/ui/WalletScreen.kt | 315 +----------- .../wallet/viewmodels/WalletViewModel.kt | 8 - 98 files changed, 15 insertions(+), 6216 deletions(-) delete mode 100644 features/manage-tokens/.gitignore delete mode 100644 features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/featuretoggles/ManageTokensFeatureToggles.kt delete mode 100644 features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/navigation/ExpandableState.kt delete mode 100644 features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/navigation/ManageTokensUi.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/di/ManageTokensFeatureTogglesModule.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/di/ManageTokensRouterModule.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/featuretoggles/DefaultManageTokensFeatureToggles.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/router/AddCustomTokenRoute.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/router/AddCustomTokenRouter.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/AddCustomTokenState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/AddCustomTokenWarning.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ButtonState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ChooseDerivationState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ChooseNetworkState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/CustomTokenData.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/Derivation.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/EnterCustomDerivationState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/TextFieldState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/AddCustomTokenStateFactory.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/AddCustomTokenStateToCryptoCurrencyConverter.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/ContractAddressToCustomTokenDataConverter.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/FoundTokenToCustomTokenDataConverter.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/NetworkToNetworkItemStateConverter.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/AddCustomTokenPreviewData.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/ChooseDerivationPreviewData.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/ChooseNetworkCustomPreviewData.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenBottomSheet.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenScreen.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/ChooseDerivationScreen.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/ChooseNetworkCustomScreen.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/CustomDerivationDialog.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/CustomTokenChooseWalletScreen.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/TokenTextField.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/viewmodels/AddCustomTokenClickIntents.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/viewmodels/AddCustomTokenViewModel.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/analytics/ManageTokens.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/AlertState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/ChooseWalletState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/Event.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/NetworkItemState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/WalletState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/previewdata/ChooseWalletStatePreviewData.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/ChooseWalletBottomSheet.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/ChooseWalletScreen.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/EventEffect.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/Alert.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/NetworkItem.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/SimpleSelectionBlock.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/utils/CurrencyUtils.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/ChooseNetworkState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/DerivationNotificationState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/ManageTokensState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/QuotesState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/SearchBarState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenButtonType.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenIconState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenItemState.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/ManageTokensStateFactory.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/NetworkToNetworkItemStateConverter.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/NetworksToChooseNetworkStateConverter.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/QuotesToQuotesStateConverter.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/TokenConverter.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/TokenToCryptoCurrencyConverter.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/ChooseNetworkStatePreviewData.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/DerivationNotificationStatePreviewData.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/ManageTokensStatePreviewData.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/TokenItemStatePreviewData.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ChooseNetworkBottomSheet.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ChooseNetworkScreen.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ManageTokensScreen.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/AddCustomTokenButton.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/DerivationNotification.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/PriceChangesChart.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/SearchBar.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenButton.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenIcon.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenPriceChange.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenRowItem.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokensList.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensClickIntents.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensUiEvents.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensViewModel.kt delete mode 100644 features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/router/ManageTokensUiImpl.kt diff --git a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt index aec8799cdd..967026bf4c 100644 --- a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt +++ b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt @@ -31,7 +31,6 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.features.details.DetailsFeatureToggles -import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles import com.tangem.features.send.api.featuretoggles.SendFeatureToggles import com.tangem.tap.domain.walletconnect2.domain.WalletConnectSessionsRepository @@ -63,8 +62,6 @@ interface ApplicationEntryPoint { fun getWalletConnectSessionsRepository(): WalletConnectSessionsRepository - fun getManageTokensFeatureToggles(): ManageTokensFeatureToggles - fun getScanCardProcessor(): ScanCardProcessor fun getAppCurrencyRepository(): AppCurrencyRepository diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index dddfa0a863..1a6869a4a5 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -50,7 +50,6 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.feature.qrscanning.QrScanningRouter import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent import com.tangem.features.disclaimer.api.DisclaimerRouter -import com.tangem.features.managetokens.navigation.ManageTokensUi import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter import com.tangem.features.send.api.navigation.SendRouter import com.tangem.features.staking.api.navigation.StakingRouter @@ -133,9 +132,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac @Inject lateinit var tokenDetailsRouter: TokenDetailsRouter - @Inject - lateinit var manageTokensUi: ManageTokensUi - @Inject lateinit var walletConnectInteractor: WalletConnectInteractor @@ -297,7 +293,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac walletRouter = walletRouter, walletConnectInteractor = walletConnectInteractor, tokenDetailsRouter = tokenDetailsRouter, - manageTokensUi = manageTokensUi, cardSdkConfigRepository = cardSdkConfigRepository, sendRouter = sendRouter, qrScanningRouter = qrScanningRouter, diff --git a/app/src/main/java/com/tangem/tap/TangemApplication.kt b/app/src/main/java/com/tangem/tap/TangemApplication.kt index d92288e204..6d94e69c9d 100644 --- a/app/src/main/java/com/tangem/tap/TangemApplication.kt +++ b/app/src/main/java/com/tangem/tap/TangemApplication.kt @@ -46,7 +46,6 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.features.details.DetailsFeatureToggles -import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles import com.tangem.features.send.api.featuretoggles.SendFeatureToggles import com.tangem.tap.common.analytics.AnalyticsFactory @@ -112,9 +111,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory { private val walletConnectSessionsRepository: WalletConnectSessionsRepository get() = entryPoint.getWalletConnectSessionsRepository() - private val manageTokensFeatureToggles: ManageTokensFeatureToggles - get() = entryPoint.getManageTokensFeatureToggles() - private val scanCardProcessor: ScanCardProcessor get() = entryPoint.getScanCardProcessor() @@ -267,7 +263,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory { customTokenFeatureToggles = customTokenFeatureToggles, walletConnectRepository = walletConnect2Repository, walletConnectSessionsRepository = walletConnectSessionsRepository, - manageTokensFeatureToggles = manageTokensFeatureToggles, scanCardProcessor = scanCardProcessor, appCurrencyRepository = appCurrencyRepository, walletManagersFacade = walletManagersFacade, diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt index cfd8b41b5f..a141560335 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt @@ -5,7 +5,6 @@ import com.tangem.domain.card.ScanCardUseCase import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.feature.qrscanning.QrScanningRouter import com.tangem.features.disclaimer.api.DisclaimerRouter -import com.tangem.features.managetokens.navigation.ManageTokensUi import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter import com.tangem.features.send.api.navigation.SendRouter import com.tangem.features.staking.api.navigation.StakingRouter @@ -23,7 +22,6 @@ sealed interface DaggerGraphAction : Action { val walletRouter: WalletRouter, val walletConnectInteractor: WalletConnectInteractor, val tokenDetailsRouter: TokenDetailsRouter, - val manageTokensUi: ManageTokensUi, val cardSdkConfigRepository: CardSdkConfigRepository, val sendRouter: SendRouter, val qrScanningRouter: QrScanningRouter, diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt index 0f98fea5e6..77f2897541 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt @@ -18,7 +18,6 @@ object DaggerGraphReducer { walletRouter = action.walletRouter, walletConnectInteractor = action.walletConnectInteractor, tokenDetailsRouter = action.tokenDetailsRouter, - manageTokensUi = action.manageTokensUi, cardSdkConfigRepository = action.cardSdkConfigRepository, sendRouter = action.sendRouter, qrScanningRouter = action.qrScanningRouter, diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index 6ca986bc42..80779536e5 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -31,8 +31,6 @@ import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.feature.qrscanning.QrScanningRouter import com.tangem.features.details.DetailsFeatureToggles import com.tangem.features.disclaimer.api.DisclaimerRouter -import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles -import com.tangem.features.managetokens.navigation.ManageTokensUi import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter import com.tangem.features.send.api.featuretoggles.SendFeatureToggles @@ -58,8 +56,6 @@ data class DaggerGraphState( val walletConnectSessionsRepository: WalletConnectSessionsRepository? = null, val walletConnectInteractor: WalletConnectInteractor? = null, val tokenDetailsRouter: TokenDetailsRouter? = null, - val manageTokensFeatureToggles: ManageTokensFeatureToggles? = null, - val manageTokensUi: ManageTokensUi? = null, val scanCardProcessor: ScanCardProcessor? = null, val cardSdkConfigRepository: CardSdkConfigRepository? = null, val appCurrencyRepository: AppCurrencyRepository? = null, diff --git a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json index 1bb02865e0..1afb6daf70 100644 --- a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json @@ -3,10 +3,6 @@ "name": "NEW_CARD_SCANNING_ENABLED", "version": "undefined" }, - { - "name": "REDESIGNED_MANAGE_TOKENS_SCREEN_ENABLED", - "version": "undefined" - }, { "name": "REDESIGNED_SEND_SCREEN_ENABLED", "version": "5.10.0" diff --git a/features/manage-tokens/.gitignore b/features/manage-tokens/.gitignore deleted file mode 100644 index 42afabfd2a..0000000000 --- a/features/manage-tokens/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/featuretoggles/ManageTokensFeatureToggles.kt b/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/featuretoggles/ManageTokensFeatureToggles.kt deleted file mode 100644 index e29173b5fc..0000000000 --- a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/featuretoggles/ManageTokensFeatureToggles.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.features.managetokens.featuretoggles - -interface ManageTokensFeatureToggles { - val isRedesignedScreenEnabled: Boolean -} \ No newline at end of file diff --git a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/navigation/ExpandableState.kt b/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/navigation/ExpandableState.kt deleted file mode 100644 index 34048e6f11..0000000000 --- a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/navigation/ExpandableState.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.tangem.features.managetokens.navigation - -enum class ExpandableState { - EXPANDED, - COLLAPSED, -} \ No newline at end of file diff --git a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/navigation/ManageTokensUi.kt b/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/navigation/ManageTokensUi.kt deleted file mode 100644 index f200ab6a3c..0000000000 --- a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/navigation/ManageTokensUi.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.tangem.features.managetokens.navigation - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.State -import androidx.compose.ui.unit.Dp - -interface ManageTokensUi { - - @Suppress("TopLevelComposableFunctions") - @Composable - fun Content(onHeaderSizeChange: (Dp) -> Unit, state: State) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/di/ManageTokensFeatureTogglesModule.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/di/ManageTokensFeatureTogglesModule.kt deleted file mode 100644 index 7552eb21df..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/di/ManageTokensFeatureTogglesModule.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.managetokens.di - -import com.tangem.core.featuretoggle.manager.FeatureTogglesManager -import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles -import com.tangem.managetokens.featuretoggles.DefaultManageTokensFeatureToggles -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 ManageTokensFeatureTogglesModule { - - @Provides - @Singleton - fun provideWalletFeatureToggles(featureTogglesManager: FeatureTogglesManager): ManageTokensFeatureToggles { - return DefaultManageTokensFeatureToggles(featureTogglesManager = featureTogglesManager) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/di/ManageTokensRouterModule.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/di/ManageTokensRouterModule.kt deleted file mode 100644 index e0ca63c3b2..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/di/ManageTokensRouterModule.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.managetokens.di - -import com.tangem.features.managetokens.navigation.ManageTokensUi -import com.tangem.managetokens.presentation.router.ManageTokensUiImpl -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -internal interface ManageTokensRouterModule { - - @Binds - @Singleton - fun provideManageTokensRouter(manageTokensUiImpl: ManageTokensUiImpl): ManageTokensUi -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/featuretoggles/DefaultManageTokensFeatureToggles.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/featuretoggles/DefaultManageTokensFeatureToggles.kt deleted file mode 100644 index 967a54e950..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/featuretoggles/DefaultManageTokensFeatureToggles.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.managetokens.featuretoggles - -import com.tangem.core.featuretoggle.manager.FeatureTogglesManager -import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles - -internal class DefaultManageTokensFeatureToggles( - private val featureTogglesManager: FeatureTogglesManager, -) : ManageTokensFeatureToggles { - override val isRedesignedScreenEnabled: Boolean - get() = featureTogglesManager.isFeatureEnabled(name = "REDESIGNED_MANAGE_TOKENS_SCREEN_ENABLED") -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/router/AddCustomTokenRoute.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/router/AddCustomTokenRoute.kt deleted file mode 100644 index fad644416a..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/router/AddCustomTokenRoute.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.router - -/** - * Add Custom Tokens screens - * @property route route string representation - */ -internal sealed class AddCustomTokenRoute(val route: String) { - object Main : AddCustomTokenRoute("$BASE_ROUTE/main") - object ChooseNetwork : AddCustomTokenRoute("$BASE_ROUTE/choose_network") - object ChooseWallet : AddCustomTokenRoute("$BASE_ROUTE/choose_wallet") - object ChooseDerivation : AddCustomTokenRoute("$BASE_ROUTE/choose_derivation") -} - -private const val BASE_ROUTE = "manage_tokens/add_custom_token" \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/router/AddCustomTokenRouter.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/router/AddCustomTokenRouter.kt deleted file mode 100644 index 4185ccddd4..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/router/AddCustomTokenRouter.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.router - -import androidx.compose.runtime.Stable -import androidx.navigation.NavController - -@Stable -internal class AddCustomTokenRouter( - private val navController: NavController, -) { - /** Pop back stack */ - fun popBackStack() { - navController.popBackStack() - } - - /** Open custom token choose network screen */ - fun openCustomTokenChooseNetwork() { - navController.navigate(AddCustomTokenRoute.ChooseNetwork.route) - } - - /** Open custom token choose derivation screen */ - fun openCustomTokenChooseDerivation() { - navController.navigate(AddCustomTokenRoute.ChooseDerivation.route) - } - - /** Open custom token choose wallet screen */ - fun openCustomTokenChooseWallet() { - navController.navigate(AddCustomTokenRoute.ChooseWallet.route) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/AddCustomTokenState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/AddCustomTokenState.kt deleted file mode 100644 index 0eafc00654..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/AddCustomTokenState.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state - -import com.tangem.core.ui.event.StateEvent -import com.tangem.core.ui.event.consumedEvent -import com.tangem.managetokens.presentation.common.state.ChooseWalletState -import com.tangem.managetokens.presentation.common.state.Event -import kotlinx.collections.immutable.ImmutableSet - -internal data class AddCustomTokenState( - val chooseWalletState: ChooseWalletState, - val chooseNetworkState: ChooseNetworkState, - val chooseDerivationState: ChooseDerivationState?, - val tokenData: CustomTokenData?, - val warnings: ImmutableSet, - val addTokenButton: ButtonState, - val showChooseWalletScreen: Boolean = false, - val event: StateEvent = consumedEvent(), -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/AddCustomTokenWarning.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/AddCustomTokenWarning.kt deleted file mode 100644 index 690178c20d..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/AddCustomTokenWarning.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state - -import com.tangem.core.ui.extensions.TextReference -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.wrappedList -import com.tangem.features.managetokens.impl.R - -/** - * Warning model of add custom token screen - * - * @property title warning description - */ -internal sealed class AddCustomTokenWarning(val title: TextReference, val subtitle: TextReference? = null) { - - object PotentialScamToken : AddCustomTokenWarning( - title = resourceReference(R.string.custom_token_validation_error_not_found_title), - subtitle = resourceReference(R.string.custom_token_validation_error_not_found_description), - ) - - object InvalidContractAddress : AddCustomTokenWarning( - title = resourceReference(R.string.custom_token_creation_error_invalid_contract_address), - ) - - object WrongDecimals : AddCustomTokenWarning( - title = - resourceReference(R.string.custom_token_creation_error_wrong_decimals, wrappedList(MAXIMUM_DECIMAL_NUMBER)), - ) - - private companion object { - const val MAXIMUM_DECIMAL_NUMBER = 30 - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ButtonState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ButtonState.kt deleted file mode 100644 index 42b515ea20..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ButtonState.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state - -internal data class ButtonState( - val isEnabled: Boolean, - val onClick: () -> Unit, -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ChooseDerivationState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ChooseDerivationState.kt deleted file mode 100644 index 047fae161d..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ChooseDerivationState.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state - -import kotlinx.collections.immutable.ImmutableList - -internal data class ChooseDerivationState( - val derivations: ImmutableList, - val selectedDerivation: Derivation?, - val enterCustomDerivationState: EnterCustomDerivationState?, - val onChooseDerivationClick: () -> Unit, - val onCloseChoosingDerivationClick: () -> Unit, - val onEnterCustomDerivation: () -> Unit, - val show: Boolean = false, -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ChooseNetworkState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ChooseNetworkState.kt deleted file mode 100644 index 56b993010b..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/ChooseNetworkState.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state - -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import kotlinx.collections.immutable.ImmutableList - -internal data class ChooseNetworkState( - val networks: ImmutableList, - val selectedNetwork: NetworkItemState?, - val onChooseNetworkClick: () -> Unit, - val onCloseChoosingNetworkClick: () -> Unit, - val show: Boolean = false, -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/CustomTokenData.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/CustomTokenData.kt deleted file mode 100644 index b481d6767a..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/CustomTokenData.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state - -internal data class CustomTokenData( - val contractAddressTextField: TextFieldState, - val nameTextField: TextFieldState, - val symbolTextField: TextFieldState, - val decimalsTextField: TextFieldState, -) { - - fun isRequiredInformationProvided(): Boolean { - return contractAddressTextField.isInputValid() && nameTextField.isInputValid() && - symbolTextField.isInputValid() && decimalsTextField.isInputValid() - } - - fun isNameSymbolDecimalsDisabled(): Boolean { - return nameTextField.isDisabled() && symbolTextField.isDisabled() && decimalsTextField.isDisabled() - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/Derivation.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/Derivation.kt deleted file mode 100644 index 69f41a5f08..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/Derivation.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state - -internal data class Derivation( - val networkName: String, - val standardType: String?, - val path: String, - val networkId: String?, - val onDerivationSelected: (Derivation) -> Unit, -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/EnterCustomDerivationState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/EnterCustomDerivationState.kt deleted file mode 100644 index 3b6ca1c57a..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/EnterCustomDerivationState.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state - -internal data class EnterCustomDerivationState( - val value: String, - val onValueChange: (String) -> Unit, - val confirmButtonEnabled: Boolean, - val derivationIncorrect: Boolean, - val onConfirmButtonClick: () -> Unit, - val onDismiss: () -> Unit, -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/TextFieldState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/TextFieldState.kt deleted file mode 100644 index 3068a0b6e9..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/TextFieldState.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state - -internal sealed class TextFieldState { - object Loading : TextFieldState() - - data class Editable( - val value: String, - val isEnabled: Boolean, - val error: AddCustomTokenWarning? = null, - val onValueChange: (String) -> Unit, - val onFocusExit: () -> Unit, - ) : TextFieldState() - - fun isInputValid(): Boolean = this is Editable && value.isNotBlank() && error == null - - fun isDisabled() = this is Editable && !this.isEnabled - - fun copySealed( - value: String = (this as? Editable)?.value ?: "", - isEnabled: Boolean = (this as? Editable)?.isEnabled ?: true, - error: AddCustomTokenWarning? = (this as? Editable)?.error, - onValueChange: (String) -> Unit = (this as? Editable)?.onValueChange ?: {}, - ): TextFieldState { - return when (this) { - is Editable -> this.copy( - value = value, - isEnabled = isEnabled, - error = error, - onValueChange = onValueChange, - ) - is Loading -> this - } - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/AddCustomTokenStateFactory.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/AddCustomTokenStateFactory.kt deleted file mode 100644 index 6ad1ac8e68..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/AddCustomTokenStateFactory.kt +++ /dev/null @@ -1,395 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state.factory - -import com.tangem.core.ui.event.consumedEvent -import com.tangem.core.ui.event.triggeredEvent -import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.tokens.error.AddCustomTokenError -import com.tangem.domain.tokens.model.Network -import com.tangem.domain.wallets.models.UserWallet -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.managetokens.presentation.common.state.* -import com.tangem.managetokens.presentation.addcustomtoken.state.* -import com.tangem.managetokens.presentation.addcustomtoken.viewmodels.AddCustomTokenClickIntents -import com.tangem.utils.Provider -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.persistentSetOf -import kotlinx.collections.immutable.toPersistentList -import kotlinx.collections.immutable.toPersistentSet - -@Suppress("LargeClass") -internal class AddCustomTokenStateFactory( - private val currentStateProvider: Provider, - private val clickIntents: AddCustomTokenClickIntents, -) { - - fun getInitialState(): AddCustomTokenState { - return AddCustomTokenState( - chooseWalletState = ChooseWalletState.NoSelection, - chooseNetworkState = ChooseNetworkState( - networks = persistentListOf(), - selectedNetwork = null, - onChooseNetworkClick = clickIntents::onChooseNetworkClick, - onCloseChoosingNetworkClick = clickIntents::onCloseChoosingNetworkClick, - ), - chooseDerivationState = ChooseDerivationState( - derivations = persistentListOf(), - selectedDerivation = null, - enterCustomDerivationState = null, - onChooseDerivationClick = clickIntents::onChooseDerivationClick, - onCloseChoosingDerivationClick = clickIntents::onCloseChoosingDerivationClick, - onEnterCustomDerivation = clickIntents::onEnterCustomDerivation, - ), - tokenData = null, - warnings = persistentSetOf(), - addTokenButton = ButtonState(isEnabled = false, onClick = clickIntents::onAddCustomButtonClick), - ) - } - - fun getFullState( - suitableUserWallets: List, - allUserWallets: List, - selectedWalletId: UserWalletId?, - supportedNetworks: List, - ): AddCustomTokenState { - val derivations = getListOfDerivations(supportedNetworks) - - val chooseDerivationState = createChooseDerivationState(derivations) - val networkConverter = NetworkToNetworkItemStateConverter(clickIntents::onNetworkSelected) - val networks = supportedNetworks.map { networkConverter.convert(it) } - - val chooseWalletState = getNewChooseWalletState(allUserWallets, suitableUserWallets, selectedWalletId) - - return AddCustomTokenState( - chooseWalletState = chooseWalletState, - chooseNetworkState = ChooseNetworkState( - networks = networks.toPersistentList(), - selectedNetwork = null, - onChooseNetworkClick = clickIntents::onChooseNetworkClick, - onCloseChoosingNetworkClick = clickIntents::onBack, - ), - chooseDerivationState = chooseDerivationState, - tokenData = null, - warnings = persistentSetOf(), - addTokenButton = ButtonState(isEnabled = false, onClick = clickIntents::onAddCustomButtonClick), - ) - } - - private fun getListOfDerivations( - networksListToGenerateDerivations: List, - filterOnlyHardenedDerivations: Boolean = false, - ): List { - return networksListToGenerateDerivations.mapNotNull { network -> - network.derivationPath.value?.let { rawPath -> - Derivation( - networkName = network.name, - standardType = network.standardType.name, - path = rawPath, - networkId = network.backendId, - onDerivationSelected = clickIntents::onDerivationSelected, - ) - }.takeIf { derivation -> - if (filterOnlyHardenedDerivations) { - derivation?.let { allNodesHardened(createDerivationPathOrNull(it.path)) } ?: false - } else { - true - } - } - } - } - - private fun createChooseDerivationState(derivations: List): ChooseDerivationState? { - return if (derivations.isNotEmpty()) { - ChooseDerivationState( - derivations = derivations.toPersistentList(), - selectedDerivation = null, - enterCustomDerivationState = null, - onChooseDerivationClick = clickIntents::onChooseDerivationClick, - onCloseChoosingDerivationClick = clickIntents::onBack, - onEnterCustomDerivation = clickIntents::onEnterCustomDerivation, - ) - } else { - null - } - } - - fun updateWithNewWalletSelected( - selectedWalletId: UserWalletId, - supportedNetworks: List, - ): AddCustomTokenState { - val derivations = getListOfDerivations(supportedNetworks) - - val chooseDerivationState = createChooseDerivationState(derivations) - val networkConverter = NetworkToNetworkItemStateConverter(clickIntents::onNetworkSelected) - val networks = supportedNetworks.map { networkConverter.convert(it) } - - val currentWalletState = requireNotNull( - currentStateProvider().chooseWalletState as? ChooseWalletState.Choose, - ) { - "If user wallet was chosen, ChooseWalletState type must be Choose" - } - val selectedWalletState = currentWalletState.wallets.find { it.walletId == selectedWalletId.stringValue } - val chooseWalletState = currentWalletState.copy(selectedWallet = selectedWalletState) - - return AddCustomTokenState( - chooseWalletState = chooseWalletState, - chooseNetworkState = ChooseNetworkState( - networks = networks.toPersistentList(), - selectedNetwork = null, - onChooseNetworkClick = clickIntents::onChooseNetworkClick, - onCloseChoosingNetworkClick = clickIntents::onBack, - ), - chooseDerivationState = chooseDerivationState, - tokenData = null, - warnings = persistentSetOf(), - addTokenButton = ButtonState(isEnabled = false, onClick = clickIntents::onAddCustomButtonClick), - ) - } - - private fun getNewChooseWalletState( - suitableUserWallets: List, - allUserWallets: List, - selectedWalletId: UserWalletId?, - ): ChooseWalletState { - val chooseWalletState = if (suitableUserWallets.size == 1) { - ChooseWalletState.NoSelection - } else if (suitableUserWallets.isEmpty() && allUserWallets.all { !it.isMultiCurrency }) { - ChooseWalletState.Warning(ChooseWalletWarning.SINGLE_CURRENCY) - } else { - var selectedWalletState: WalletState? = null - ChooseWalletState.Choose( - wallets = suitableUserWallets.map { wallet -> - val walletState = WalletState( - walletId = wallet.walletId.stringValue, - artworkUrl = wallet.artworkUrl, - onSelected = clickIntents::onWalletSelected, - walletName = wallet.name, - ) - if (wallet.walletId.stringValue == selectedWalletId?.stringValue) { - selectedWalletState = walletState - } - walletState - }.toPersistentList(), - selectedWallet = requireNotNull(selectedWalletState), - onChooseWalletClick = clickIntents::onChooseWalletClick, - onCloseChoosingWalletClick = clickIntents::onCloseChoosingWalletClick, - ) - } - return chooseWalletState - } - - fun removeTokenAddressError(): AddCustomTokenState { - return addTokenAddressFieldError(null) - } - - private fun addTokenAddressFieldError(error: AddCustomTokenWarning?): AddCustomTokenState { - val tokenData = currentStateProvider().tokenData ?: return currentStateProvider() - val contractAddressField = tokenData.contractAddressTextField.copySealed(error = error) - return currentStateProvider().copy(tokenData = tokenData.copy(contractAddressTextField = contractAddressField)) - } - - private fun unlockAndClearNameSymbolAndDecimals(state: AddCustomTokenState): AddCustomTokenState { - val currentTokenData = state.tokenData - return state.copy( - tokenData = currentTokenData?.copy( - nameTextField = TextFieldState.Editable( - value = "", - isEnabled = true, - onValueChange = clickIntents::onTokenNameChange, - onFocusExit = clickIntents::onTokenNameFocusExit, - ), - symbolTextField = TextFieldState.Editable( - value = "", - isEnabled = true, - onValueChange = clickIntents::onSymbolChange, - onFocusExit = clickIntents::onSymbolFocusExit, - ), - decimalsTextField = TextFieldState.Editable( - value = "", - isEnabled = true, - onValueChange = clickIntents::onDecimalsChange, - onFocusExit = clickIntents::onDecimalsFocusExit, - ), - ), - ) - } - - fun getStateAndTriggerEvent( - state: AddCustomTokenState, - event: Event, - setUiState: (AddCustomTokenState) -> Unit, - ): AddCustomTokenState { - return state.copy( - event = triggeredEvent( - data = event, - onConsume = { - val currentState = currentStateProvider() - setUiState(currentState.copy(event = consumedEvent())) - }, - ), - ) - } - - fun updateStateOnNetworkSelected( - networkItemState: NetworkItemState, - supportsTokens: Boolean, - networks: List, - requiresHardenedDerivationOnly: Boolean, - ): AddCustomTokenState { - val uiState = currentStateProvider() - val tokenData = if (supportsTokens) { - uiState.tokenData ?: CustomTokenData( - contractAddressTextField = TextFieldState.Editable( - value = "", - isEnabled = true, - onValueChange = clickIntents::onContractAddressChange, - onFocusExit = clickIntents::onContractAddressFocusExit, - ), - nameTextField = TextFieldState.Editable( - value = "", - isEnabled = false, - onValueChange = clickIntents::onTokenNameChange, - onFocusExit = clickIntents::onTokenNameFocusExit, - ), - symbolTextField = TextFieldState.Editable( - value = "", - isEnabled = false, - onValueChange = clickIntents::onSymbolChange, - onFocusExit = clickIntents::onSymbolFocusExit, - ), - decimalsTextField = TextFieldState.Editable( - value = "", - isEnabled = false, - onValueChange = clickIntents::onDecimalsChange, - onFocusExit = clickIntents::onDecimalsFocusExit, - ), - ) - } else { - null - } - - val derivations = getListOfDerivations(networks, requiresHardenedDerivationOnly) - val chooseDerivationState = createChooseDerivationState(derivations) - - return uiState.copy( - chooseNetworkState = uiState.chooseNetworkState.copy( - selectedNetwork = networkItemState, - ), - chooseDerivationState = chooseDerivationState, - tokenData = tokenData, - addTokenButton = uiState.addTokenButton.copy(isEnabled = true), - ) - } - - fun updateOnCustomDerivationSelected(): AddCustomTokenState { - val uiState = currentStateProvider() - return uiState.copy( - chooseDerivationState = uiState.chooseDerivationState?.copy( - enterCustomDerivationState = null, - selectedDerivation = Derivation( - networkName = "", - path = uiState.chooseDerivationState.enterCustomDerivationState?.value ?: "", - networkId = null, - standardType = null, - onDerivationSelected = clickIntents::onDerivationSelected, - ), - ), - ) - } - - fun updateStateOnEnterCustomDerivation(): AddCustomTokenState { - val customDerivationState = EnterCustomDerivationState( - value = "", - onValueChange = clickIntents::onCustomDerivationChange, - confirmButtonEnabled = false, - derivationIncorrect = false, - onConfirmButtonClick = clickIntents::onCustomDerivationSelected, - onDismiss = clickIntents::onCustomDerivationDialogDismissed, - ) - val uiState = currentStateProvider() - return uiState.copy( - chooseDerivationState = uiState.chooseDerivationState?.copy( - enterCustomDerivationState = customDerivationState, - ), - ) - } - - fun updateOnCustomDerivationEntered(input: String, requiresHardenedDerivationOnly: Boolean): AddCustomTokenState { - val uiState = currentStateProvider() - val path = createDerivationPathOrNull(input) - val isWrongDerivationForWallet2 = isWrongDerivationForWallet2( - requiresHardenedDerivationOnly = requiresHardenedDerivationOnly, - derivationPath = path, - ) - val enterDerivationState = uiState.chooseDerivationState?.enterCustomDerivationState?.copy( - confirmButtonEnabled = path != null && !isWrongDerivationForWallet2, - derivationIncorrect = input.isNotBlank() && path == null || isWrongDerivationForWallet2, - ) - return uiState.copy( - chooseDerivationState = uiState.chooseDerivationState?.copy( - enterCustomDerivationState = enterDerivationState, - ), - ) - } - - private fun isWrongDerivationForWallet2( - requiresHardenedDerivationOnly: Boolean, - derivationPath: DerivationPath?, - ): Boolean { - return if (requiresHardenedDerivationOnly) { - !allNodesHardened(derivationPath) - } else { - false - } - } - - private fun allNodesHardened(derivationPath: DerivationPath?): Boolean { - return derivationPath?.nodes?.all { it.isHardened } ?: false - } - - private fun createDerivationPathOrNull(rawPath: String): DerivationPath? { - return try { - DerivationPath(rawPath) - } catch (error: Throwable) { - null - } - } - - fun updateStateOnLoadingTokenInfo(contractAddress: String): AddCustomTokenState { - return currentStateProvider().copy( - tokenData = CustomTokenData( - contractAddressTextField = TextFieldState.Editable( - value = contractAddress, - isEnabled = true, - onValueChange = clickIntents::onContractAddressChange, - onFocusExit = clickIntents::onContractAddressFocusExit, - - ), - nameTextField = TextFieldState.Loading, - symbolTextField = TextFieldState.Loading, - decimalsTextField = TextFieldState.Loading, - ), - ) - } - - fun handleAddressError(error: AddCustomTokenError): AddCustomTokenState { - val uiState = currentStateProvider() - return when (error) { - AddCustomTokenError.INVALID_CONTRACT_ADDRESS -> { - removeTokenAddressError().also { unlockAndClearNameSymbolAndDecimals(it) } - .copy( - addTokenButton = uiState.addTokenButton.copy(isEnabled = false), - warnings = uiState.warnings - .filterNot { it is AddCustomTokenWarning.PotentialScamToken } - .toPersistentSet(), - ) - } - AddCustomTokenError.FIELD_IS_EMPTY -> - removeTokenAddressError().also { unlockAndClearNameSymbolAndDecimals(it) } - .copy( - addTokenButton = uiState.addTokenButton.copy( - isEnabled = uiState.tokenData?.isRequiredInformationProvided() == true, - ), - ) - } - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/AddCustomTokenStateToCryptoCurrencyConverter.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/AddCustomTokenStateToCryptoCurrencyConverter.kt deleted file mode 100644 index e6e1b2f84e..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/AddCustomTokenStateToCryptoCurrencyConverter.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state.factory - -import com.tangem.data.tokens.utils.CryptoCurrencyFactory -import com.tangem.domain.common.DerivationStyleProvider -import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.managetokens.presentation.addcustomtoken.state.AddCustomTokenState -import com.tangem.managetokens.presentation.addcustomtoken.state.CustomTokenData -import com.tangem.managetokens.presentation.addcustomtoken.state.TextFieldState -import com.tangem.utils.converter.Converter - -internal class AddCustomTokenStateToCryptoCurrencyConverter( - private val derivationStyleProvider: DerivationStyleProvider, -) : Converter { - - override fun convert(value: AddCustomTokenState): CryptoCurrency { - val derivationPath = value.chooseDerivationState?.selectedDerivation?.path - val token = parseTokenOrNull(value.tokenData) - - val cryptoCurrency = if (token != null) { - CryptoCurrencyFactory().createToken( - token = token, - networkId = value.chooseNetworkState.selectedNetwork?.id ?: "", - derivationStyleProvider = derivationStyleProvider, - extraDerivationPath = derivationPath, - ) - } else { - CryptoCurrencyFactory().createCoin( - networkId = value.chooseNetworkState.selectedNetwork?.id ?: "", - derivationStyleProvider = derivationStyleProvider, - extraDerivationPath = derivationPath, - ) - } - return requireNotNull(cryptoCurrency) { - "Unless network is not Unknown blockchain, CryptoCurrency cannot be null" - } - } - - @Suppress("ComplexCondition") - private fun parseTokenOrNull(tokenData: CustomTokenData?): CryptoCurrencyFactory.Token? { - val contractAddress = (tokenData?.contractAddressTextField as? TextFieldState.Editable)?.value - val symbol = (tokenData?.symbolTextField as? TextFieldState.Editable)?.value - val name = (tokenData?.nameTextField as? TextFieldState.Editable)?.value - val decimals = (tokenData?.decimalsTextField as? TextFieldState.Editable)?.value?.toIntOrNull() - return if ( - !contractAddress.isNullOrBlank() && !symbol.isNullOrBlank() && !name.isNullOrBlank() && decimals != null - ) { - CryptoCurrencyFactory.Token( - symbol = symbol, - name = name, - contractAddress = contractAddress, - decimals = decimals, - id = null, - ) - } else { - null - } - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/ContractAddressToCustomTokenDataConverter.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/ContractAddressToCustomTokenDataConverter.kt deleted file mode 100644 index eb0897d370..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/ContractAddressToCustomTokenDataConverter.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state.factory - -import com.tangem.managetokens.presentation.addcustomtoken.state.CustomTokenData -import com.tangem.managetokens.presentation.addcustomtoken.state.TextFieldState -import com.tangem.managetokens.presentation.addcustomtoken.viewmodels.AddCustomTokenClickIntents -import com.tangem.utils.converter.Converter - -internal class ContractAddressToCustomTokenDataConverter( - private val clickIntents: AddCustomTokenClickIntents, -) : Converter { - override fun convert(value: String): CustomTokenData { - return CustomTokenData( - contractAddressTextField = TextFieldState.Editable( - value = value, - isEnabled = true, - onValueChange = clickIntents::onContractAddressChange, - onFocusExit = clickIntents::onContractAddressFocusExit, - ), - nameTextField = TextFieldState.Editable( - value = "", - isEnabled = true, - onValueChange = clickIntents::onTokenNameChange, - onFocusExit = clickIntents::onTokenNameFocusExit, - ), - symbolTextField = TextFieldState.Editable( - value = "", - isEnabled = true, - onValueChange = clickIntents::onSymbolChange, - onFocusExit = clickIntents::onSymbolFocusExit, - ), - decimalsTextField = TextFieldState.Editable( - value = "", - isEnabled = true, - onValueChange = clickIntents::onDecimalsChange, - onFocusExit = clickIntents::onDecimalsFocusExit, - ), - ) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/FoundTokenToCustomTokenDataConverter.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/FoundTokenToCustomTokenDataConverter.kt deleted file mode 100644 index 65921700dc..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/FoundTokenToCustomTokenDataConverter.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state.factory - -import com.tangem.domain.tokens.model.FoundToken -import com.tangem.managetokens.presentation.addcustomtoken.state.CustomTokenData -import com.tangem.managetokens.presentation.addcustomtoken.state.TextFieldState -import com.tangem.managetokens.presentation.addcustomtoken.viewmodels.AddCustomTokenClickIntents -import com.tangem.utils.converter.Converter - -internal class FoundTokenToCustomTokenDataConverter( - private val clickIntents: AddCustomTokenClickIntents, -) : Converter { - override fun convert(value: FoundToken): CustomTokenData { - return CustomTokenData( - contractAddressTextField = TextFieldState.Editable( - value = value.contractAddress, - isEnabled = true, - onValueChange = clickIntents::onContractAddressChange, - onFocusExit = clickIntents::onContractAddressFocusExit, - ), - nameTextField = TextFieldState.Editable( - value = value.name, - isEnabled = false, - onValueChange = clickIntents::onTokenNameChange, - onFocusExit = clickIntents::onTokenNameFocusExit, - ), - symbolTextField = TextFieldState.Editable( - value = value.symbol, - isEnabled = false, - onValueChange = clickIntents::onSymbolChange, - onFocusExit = clickIntents::onSymbolFocusExit, - ), - decimalsTextField = TextFieldState.Editable( - value = value.decimals.toString(), - isEnabled = false, - onValueChange = clickIntents::onDecimalsChange, - onFocusExit = clickIntents::onDecimalsFocusExit, - ), - ) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/NetworkToNetworkItemStateConverter.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/NetworkToNetworkItemStateConverter.kt deleted file mode 100644 index 74b4eda971..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/factory/NetworkToNetworkItemStateConverter.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state.factory - -import com.tangem.core.ui.extensions.getActiveIconResByNetworkId -import com.tangem.domain.tokens.model.Network -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import com.tangem.utils.converter.Converter - -internal class NetworkToNetworkItemStateConverter( - private val onNetworkItemSelected: (NetworkItemState) -> Unit, -) : Converter { - override fun convert(value: Network): NetworkItemState { - return NetworkItemState.Selectable( - name = value.name, - protocolName = value.standardType.name, - iconResId = getActiveIconResByNetworkId(value.backendId), - id = value.backendId, - onNetworkClick = onNetworkItemSelected, - ) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/AddCustomTokenPreviewData.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/AddCustomTokenPreviewData.kt deleted file mode 100644 index 96e7bf7379..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/AddCustomTokenPreviewData.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state.previewdata - -import com.tangem.managetokens.presentation.common.state.ChooseWalletState -import com.tangem.managetokens.presentation.common.state.WalletState -import com.tangem.managetokens.presentation.addcustomtoken.state.* -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.persistentSetOf - -internal object AddCustomTokenPreviewData { - val state = AddCustomTokenState( - chooseWalletState = ChooseWalletState.Choose( - wallets = persistentListOf(), - selectedWallet = WalletState( - "", - "", - "My Wallet", - {}, - ), - onChooseWalletClick = { }, - onCloseChoosingWalletClick = { }, - ), - chooseNetworkState = ChooseNetworkState( - networks = persistentListOf(), - selectedNetwork = null, - onChooseNetworkClick = { }, - onCloseChoosingNetworkClick = {}, - ), - chooseDerivationState = ChooseDerivationState( - derivations = persistentListOf(), - selectedDerivation = null, - enterCustomDerivationState = null, - onChooseDerivationClick = { }, - onCloseChoosingDerivationClick = {}, - onEnterCustomDerivation = {}, - ), - tokenData = CustomTokenData( - contractAddressTextField = TextFieldState.Editable( - value = "0x4ace7262705b68bcba5b91de96889349394", - isEnabled = false, - onValueChange = {}, - onFocusExit = {}, - ), - nameTextField = TextFieldState.Loading, - symbolTextField = TextFieldState.Loading, - decimalsTextField = TextFieldState.Loading, - ), - warnings = persistentSetOf(), - addTokenButton = ButtonState(isEnabled = true, onClick = {}), - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/ChooseDerivationPreviewData.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/ChooseDerivationPreviewData.kt deleted file mode 100644 index c4cfd15483..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/ChooseDerivationPreviewData.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state.previewdata - -import com.tangem.managetokens.presentation.addcustomtoken.state.ChooseDerivationState -import com.tangem.managetokens.presentation.addcustomtoken.state.Derivation -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf - -internal object ChooseDerivationPreviewData { - private val derivations: ImmutableList = persistentListOf( - Derivation( - networkName = "Ethereum", - path = "m/44’/9001’/0’/0/0", - networkId = "ethereum", - standardType = "ERC", - onDerivationSelected = {}, - ), - Derivation( - networkName = "Polygon", - path = "m/44’/9001’/0’/0/0", - networkId = "polygon", - standardType = "ERC", - onDerivationSelected = {}, - ), - Derivation( - networkName = "Avalanche", - path = "m/44’/9001’/0’/0/0", - networkId = "avalanche", - standardType = "ERC", - onDerivationSelected = {}, - ), - ) - - val state = ChooseDerivationState( - derivations = derivations, - selectedDerivation = derivations.first(), - enterCustomDerivationState = null, - onEnterCustomDerivation = {}, - onCloseChoosingDerivationClick = {}, - onChooseDerivationClick = {}, - show = true, - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/ChooseNetworkCustomPreviewData.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/ChooseNetworkCustomPreviewData.kt deleted file mode 100644 index 08987dbadf..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/state/previewdata/ChooseNetworkCustomPreviewData.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.state.previewdata - -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import com.tangem.managetokens.presentation.addcustomtoken.state.ChooseNetworkState -import kotlinx.collections.immutable.persistentListOf - -internal object ChooseNetworkCustomPreviewData { - val networks = persistentListOf( - NetworkItemState.Selectable( - name = "Ethereum", - protocolName = "ETH", - iconResId = R.drawable.img_kusama_22, - id = "ethereum", - onNetworkClick = { }, - ), - NetworkItemState.Selectable( - name = "BNB SMART CHAIN", - protocolName = "BEP20", - iconResId = R.drawable.ic_bsc_16, - id = "binance smart chain", - onNetworkClick = { }, - ), - ) - val state = ChooseNetworkState( - networks, - selectedNetwork = networks.first(), - onCloseChoosingNetworkClick = {}, - onChooseNetworkClick = {}, - show = true, - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenBottomSheet.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenBottomSheet.kt deleted file mode 100644 index 95dfd58871..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenBottomSheet.kt +++ /dev/null @@ -1,202 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.ui - -import android.annotation.SuppressLint -import androidx.activity.compose.BackHandler -import androidx.activity.compose.LocalOnBackPressedDispatcherOwner -import androidx.compose.foundation.focusable -import androidx.compose.foundation.layout.* -import androidx.compose.material3.BottomSheetDefaults -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.ModalBottomSheetDefaults -import androidx.compose.material3.ModalBottomSheetProperties -import androidx.compose.material3.SheetState -import androidx.compose.material3.SheetValue -import androidx.compose.material3.rememberModalBottomSheetState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.input.key.Key -import androidx.compose.ui.input.key.KeyEventType -import androidx.compose.ui.input.key.key -import androidx.compose.ui.input.key.onPreviewKeyEvent -import androidx.compose.ui.input.key.type -import androidx.compose.ui.platform.LocalDensity -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable -import androidx.navigation.compose.rememberNavController -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetDraggableHeader -import com.tangem.core.ui.components.bottomsheets.collapse -import com.tangem.core.ui.res.LocalWindowSize -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.utils.WindowInsetsZero -import com.tangem.managetokens.presentation.addcustomtoken.router.AddCustomTokenRoute -import com.tangem.managetokens.presentation.addcustomtoken.router.AddCustomTokenRouter -import com.tangem.managetokens.presentation.addcustomtoken.viewmodels.AddCustomTokenViewModel -import com.tangem.managetokens.presentation.common.state.ChooseWalletState -import kotlinx.coroutines.launch - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun AddCustomTokenBottomSheet(config: TangemBottomSheetConfig) { - val viewModel = hiltViewModel() - - var isVisible by remember { mutableStateOf(value = config.isShow) } - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - val statusBarHeight = with(LocalDensity.current) { WindowInsets.statusBars.getTop(this).toDp() } - - if (isVisible) { - // ViewModel cannot be scoped to ModalBottomSheet's lifecycle, - // so we have to manually initialize and dispose its state when bottom sheet enters and leaves a composition - DisposableEffect(viewModel) { - viewModel.onInitialize() - onDispose { viewModel.onDispose() } - } - - ModalBottomSheetWithBackHandling( - modifier = Modifier - .sizeIn(maxHeight = LocalWindowSize.current.height - statusBarHeight), - onDismissRequest = config.onDismissRequest, - sheetState = sheetState, - containerColor = TangemTheme.colors.background.tertiary, - shape = TangemTheme.shapes.bottomSheetLarge, - windowInsets = WindowInsetsZero, - dragHandle = { TangemBottomSheetDraggableHeader(color = TangemTheme.colors.background.tertiary) }, - properties = ModalBottomSheetDefaults.properties(shouldDismissOnBackPress = false), - ) { - Content(onDismissRequest = config.onDismissRequest, viewModel = viewModel) - } - } - - LaunchedEffect(key1 = config.isShow) { - if (config.isShow) { - isVisible = true - } else { - sheetState.collapse { isVisible = false } - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun ModalBottomSheetWithBackHandling( - onDismissRequest: () -> Unit, - modifier: Modifier = Modifier, - containerColor: Color = BottomSheetDefaults.ContainerColor, - shape: Shape = BottomSheetDefaults.ExpandedShape, - windowInsets: WindowInsets = BottomSheetDefaults.windowInsets, - dragHandle: @Composable (() -> Unit)? = { BottomSheetDefaults.DragHandle() }, - sheetState: SheetState = rememberModalBottomSheetState(), - properties: ModalBottomSheetProperties = ModalBottomSheetDefaults.properties(), - content: @Composable ColumnScope.() -> Unit, -) { - val scope = rememberCoroutineScope() - - BackHandler(enabled = sheetState.targetValue != SheetValue.Hidden) { - // Always catch back here, but only let it dismiss if shouldDismissOnBackPress. - // If not, it will have no effect. - if (properties.shouldDismissOnBackPress) { - scope.launch { sheetState.hide() }.invokeOnCompletion { - if (!sheetState.isVisible) { - onDismissRequest() - } - } - } - } - - val requester = remember { FocusRequester() } - val backPressedDispatcherOwner = LocalOnBackPressedDispatcherOwner.current - - ModalBottomSheet( - onDismissRequest = onDismissRequest, - containerColor = containerColor, - shape = shape, - windowInsets = windowInsets, - dragHandle = dragHandle, - sheetState = sheetState, - modifier = modifier - .focusRequester(requester) - .focusable() - .onPreviewKeyEvent { - if (it.key == Key.Back && it.type == KeyEventType.KeyUp && !it.nativeKeyEvent.isCanceled) { - backPressedDispatcherOwner?.onBackPressedDispatcher?.onBackPressed() - return@onPreviewKeyEvent true - } - return@onPreviewKeyEvent false - }, - properties = ModalBottomSheetDefaults.properties( - securePolicy = properties.securePolicy, - isFocusable = properties.isFocusable, - // Set false otherwise the onPreviewKeyEvent doesn't work at all. - // The functionality of shouldDismissOnBackPress is achieved by the BackHandler. - shouldDismissOnBackPress = false, - ), - content = content, - ) - - LaunchedEffect(Unit) { - requester.requestFocus() - } -} - -@SuppressLint("RestrictedApi") -@Composable -private fun Content(viewModel: AddCustomTokenViewModel, onDismissRequest: () -> Unit) { - val navController = rememberNavController() - - LaunchedEffect(navController) { - navController.currentBackStack - .collect { - if (it.isEmpty()) { - onDismissRequest() - } - } - } - - BackHandler(true) { - navController.popBackStack() - } - - val router = remember(navController) { AddCustomTokenRouter(navController) } - - viewModel.router = router - - NavHost( - modifier = Modifier.fillMaxSize(), - navController = navController, - startDestination = AddCustomTokenRoute.Main.route, - ) { - composable( - route = AddCustomTokenRoute.Main.route, - ) { - AddCustomTokenScreen(state = viewModel.uiState) - } - composable( - route = AddCustomTokenRoute.ChooseNetwork.route, - ) { - ChooseNetworkCustomScreen(state = viewModel.uiState.chooseNetworkState) - } - composable( - route = AddCustomTokenRoute.ChooseDerivation.route, - ) { - ChooseDerivationScreen(state = requireNotNull(viewModel.uiState.chooseDerivationState)) - } - composable( - route = AddCustomTokenRoute.ChooseWallet.route, - ) { - CustomTokensChooseWalletScreen(state = viewModel.uiState.chooseWalletState as ChooseWalletState.Choose) - } - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenScreen.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenScreen.kt deleted file mode 100644 index d5691e9017..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/AddCustomTokenScreen.kt +++ /dev/null @@ -1,298 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.ui - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.Text -import androidx.compose.runtime.* -import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.focus.FocusDirection -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.Keyboard -import com.tangem.core.ui.components.PrimaryButton -import com.tangem.core.ui.components.RectangleShimmer -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig -import com.tangem.core.ui.components.keyboardAsState -import com.tangem.core.ui.extensions.resolveReference -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.common.state.AlertState -import com.tangem.managetokens.presentation.common.state.ChooseWalletState -import com.tangem.managetokens.presentation.common.ui.ChooseWalletBottomSheet -import com.tangem.managetokens.presentation.common.ui.ChooseWalletBottomSheetConfig -import com.tangem.managetokens.presentation.common.ui.EventEffect -import com.tangem.managetokens.presentation.common.ui.components.Alert -import com.tangem.managetokens.presentation.common.ui.components.SimpleSelectionBlock -import com.tangem.managetokens.presentation.addcustomtoken.state.AddCustomTokenState -import com.tangem.managetokens.presentation.addcustomtoken.state.CustomTokenData -import com.tangem.managetokens.presentation.addcustomtoken.state.TextFieldState -import com.tangem.managetokens.presentation.addcustomtoken.state.previewdata.AddCustomTokenPreviewData - -@Composable -internal fun AddCustomTokenScreen(state: AddCustomTokenState, modifier: Modifier = Modifier) { - var alertState by remember { mutableStateOf(value = null) } - - EventEffect( - event = state.event, - onAlertStateSet = { alertState = it }, - ) - alertState?.let { - Alert(state = it, onDismiss = { alertState = null }) - } - Content(state = state, modifier = modifier) -} - -@Composable -private fun Content(state: AddCustomTokenState, modifier: Modifier = Modifier) { - val keyboard by keyboardAsState() - - Column( - modifier = modifier - .background(color = TangemTheme.colors.background.tertiary) - .statusBarsPadding() - .navigationBarsPadding() - .imePadding() - .padding( - top = TangemTheme.dimens.spacing10, - start = TangemTheme.dimens.spacing16, - end = TangemTheme.dimens.spacing16, - bottom = TangemTheme.dimens.spacing18, - ) - .fillMaxWidth(), - ) { - Text( - text = stringResource(id = R.string.manage_tokens_network_selector_title), - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.subtitle1, - textAlign = TextAlign.Center, - modifier = Modifier - .fillMaxWidth() - .padding(bottom = TangemTheme.dimens.spacing10), - ) - Text( - text = stringResource(id = R.string.custom_token_subtitle), - color = TangemTheme.colors.text.secondary, - style = TangemTheme.typography.caption2, - textAlign = TextAlign.Center, - modifier = Modifier - .fillMaxWidth() - .padding(bottom = TangemTheme.dimens.spacing16), - ) - CustomTokenItemsList(state = state) - if (keyboard is Keyboard.Closed) { - PrimaryButton( - text = stringResource(id = R.string.custom_token_add_token), - onClick = state.addTokenButton.onClick, - enabled = state.addTokenButton.isEnabled, - modifier = Modifier.fillMaxWidth(), - ) - } - } - - if (state.chooseWalletState is ChooseWalletState.Choose && state.chooseWalletState.show) { - val config = TangemBottomSheetConfig( - isShow = true, - content = ChooseWalletBottomSheetConfig(state.chooseWalletState), - onDismissRequest = state.chooseWalletState.onCloseChoosingWalletClick, - ) - ChooseWalletBottomSheet(config) - } -} - -@Composable -private fun ColumnScope.CustomTokenItemsList(state: AddCustomTokenState, modifier: Modifier = Modifier) { - LazyColumn( - modifier - .fillMaxWidth() - .weight(1f), - ) { - if (state.chooseWalletState is ChooseWalletState.Choose) { - item { - SimpleSelectionBlock( - title = stringResource(id = R.string.manage_tokens_network_selector_wallet), - subtitle = state.chooseWalletState.selectedWallet?.walletName ?: "", - onClick = state.chooseWalletState.onChooseWalletClick, - modifier = Modifier - .padding(bottom = TangemTheme.dimens.spacing12), - ) - } - } - item { - SimpleSelectionBlock( - title = stringResource(id = R.string.custom_token_network_input_title), - subtitle = state.chooseNetworkState.selectedNetwork?.name - ?: stringResource(id = R.string.manage_tokens_network_selector_title), - onClick = state.chooseNetworkState.onChooseNetworkClick, - modifier = Modifier - .padding(bottom = TangemTheme.dimens.spacing12), - ) - } - if (state.tokenData != null) { - item { - TokenFields( - state = state.tokenData, - modifier = Modifier - .padding(bottom = TangemTheme.dimens.spacing12), - ) - } - } - if (state.chooseDerivationState != null) { - item { - SimpleSelectionBlock( - title = stringResource(id = R.string.custom_token_derivation_path), - subtitle = state.chooseDerivationState.selectedDerivation?.path - ?: stringResource(id = R.string.custom_token_derivation_path_default), - onClick = state.chooseDerivationState.onChooseDerivationClick, - modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12), - ) - } - } - } -} - -@OptIn(ExperimentalComposeUiApi::class) -@Composable -private fun TokenFields(state: CustomTokenData, modifier: Modifier = Modifier) { - val focusManager = LocalFocusManager.current - - Column( - modifier = modifier - .fillMaxWidth() - .clip(shape = RoundedCornerShape(TangemTheme.dimens.radius16)) - .background(color = TangemTheme.colors.background.action), - ) { - TokenField( - textFieldState = state.contractAddressTextField, - placeholder = "0x0000000000000000000000000000000", - title = R.string.custom_token_contract_address_input_title, - keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Text, - imeAction = if (state.isNameSymbolDecimalsDisabled()) { - ImeAction.Done - } else { - ImeAction.Next - }, - ), - onImeAction = { - if (state.isNameSymbolDecimalsDisabled()) { - focusManager.moveFocus(FocusDirection.Exit) - } else { - focusManager.moveFocus(FocusDirection.Down) - } - }, - ) - TokenField( - textFieldState = state.nameTextField, - placeholder = stringResource(id = R.string.custom_token_name_input_placeholder), - title = R.string.custom_token_name_input_title, - keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Text, - imeAction = ImeAction.Next, - ), - onImeAction = { focusManager.moveFocus(FocusDirection.Down) }, - ) - TokenField( - textFieldState = state.symbolTextField, - placeholder = stringResource(id = R.string.custom_token_token_symbol_input_placeholder), - title = R.string.custom_token_token_symbol_input_title, - keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Text, - imeAction = ImeAction.Next, - ), - onImeAction = { focusManager.moveFocus(FocusDirection.Down) }, - ) - TokenField( - textFieldState = state.decimalsTextField, - placeholder = "0", - title = R.string.custom_token_decimals_input_title, - keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Number, - imeAction = ImeAction.Done, - ), - onImeAction = { focusManager.moveFocus(FocusDirection.Exit) }, - ) - } -} - -@Composable -private fun TokenField( - textFieldState: TextFieldState, - placeholder: String, - title: Int, - onImeAction: () -> Unit, - keyboardOptions: KeyboardOptions, -) { - Column( - modifier = Modifier - .background(color = TangemTheme.colors.background.action) - .padding(TangemTheme.dimens.spacing16), - ) { - TokenTextFieldTitle( - state = textFieldState, - title = stringResource(id = title), - ) - when (textFieldState) { - is TextFieldState.Editable -> TokenTextField( - state = textFieldState, - placeholder = placeholder, - onImeAction = onImeAction, - keyboardOptions = keyboardOptions, - ) - is TextFieldState.Loading -> TokenShimmer() - } - } -} - -@Composable -private fun TokenShimmer() { - RectangleShimmer( - radius = TangemTheme.dimens.radius3, - modifier = Modifier - .padding(vertical = TangemTheme.dimens.spacing4) - .size( - height = TangemTheme.dimens.size12, - width = TangemTheme.dimens.size90, - ), - ) -} - -@Composable -private fun TokenTextFieldTitle(state: TextFieldState?, title: String) { - val modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing4) - val error = (state as? TextFieldState.Editable)?.error - if (error == null) { - Text( - text = title, - color = TangemTheme.colors.text.secondary, - style = TangemTheme.typography.subtitle1, - modifier = modifier, - ) - } else { - Text( - text = error.title.resolveReference(), - color = TangemTheme.colors.text.warning, - style = TangemTheme.typography.subtitle1, - modifier = modifier, - ) - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun Preview_ChooseDerivationScreen() { - TangemThemePreview { - AddCustomTokenScreen(state = AddCustomTokenPreviewData.state) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/ChooseDerivationScreen.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/ChooseDerivationScreen.kt deleted file mode 100644 index a7805cbb96..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/ChooseDerivationScreen.kt +++ /dev/null @@ -1,109 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.ui - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -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.tooling.preview.Preview -import com.tangem.core.ui.decorations.roundedShapeItemDecoration -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.core.ui.res.TangemTheme -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.common.ui.components.SimpleSelectionBlock -import com.tangem.managetokens.presentation.addcustomtoken.state.ChooseDerivationState -import com.tangem.managetokens.presentation.addcustomtoken.state.previewdata.ChooseDerivationPreviewData - -@Composable -internal fun ChooseDerivationScreen(state: ChooseDerivationState, modifier: Modifier = Modifier) { - if (state.enterCustomDerivationState != null) { - CustomDerivationDialog(state.enterCustomDerivationState) - } - - Column( - modifier = modifier - .fillMaxSize() - .background(color = TangemTheme.colors.background.tertiary) - .statusBarsPadding() - .navigationBarsPadding() - .padding( - top = TangemTheme.dimens.spacing10, - start = TangemTheme.dimens.spacing16, - end = TangemTheme.dimens.spacing16, - bottom = TangemTheme.dimens.spacing18, - ), - ) { - Box( - modifier = Modifier - .fillMaxWidth() - .defaultMinSize(minHeight = TangemTheme.dimens.size44) - .padding(bottom = TangemTheme.dimens.spacing12), - contentAlignment = Alignment.CenterStart, - ) { - Icon( - painter = painterResource(id = R.drawable.ic_back_24), - contentDescription = null, - tint = TangemTheme.colors.icon.primary1, - modifier = Modifier - .clickable { state.onCloseChoosingDerivationClick() }, - ) - Text( - text = stringResource(id = R.string.custom_token_derivation_path), - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.subtitle1, - modifier = Modifier - .padding(horizontal = TangemTheme.dimens.spacing24) - .align(Alignment.Center), - ) - } - DerivationsList(state) - } -} - -@Composable -private fun DerivationsList(state: ChooseDerivationState) { - LazyColumn( - modifier = Modifier - .padding(horizontal = TangemTheme.dimens.spacing16), - contentPadding = PaddingValues(vertical = TangemTheme.dimens.spacing12), - ) { - item { - SimpleSelectionBlock( - title = stringResource(id = R.string.custom_token_custom_derivation), - subtitle = stringResource(id = R.string.custom_token_custom_derivation), - onClick = state.onEnterCustomDerivation, - modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12), - ) - } - items(state.derivations.count()) { index -> - val derivationItem = state.derivations[index] - SimpleSelectionBlock( - title = derivationItem.networkName, - subtitle = derivationItem.path, - onClick = { derivationItem.onDerivationSelected(derivationItem) }, - modifier = Modifier.roundedShapeItemDecoration( - currentIndex = index, - lastIndex = state.derivations.lastIndex, - addDefaultPadding = false, - ), - roundedCorners = false, - ) - } - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun Preview_ChooseDerivationScreen() { - TangemThemePreview { - ChooseDerivationScreen(state = ChooseDerivationPreviewData.state) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/ChooseNetworkCustomScreen.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/ChooseNetworkCustomScreen.kt deleted file mode 100644 index 6777fc4fbc..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/ChooseNetworkCustomScreen.kt +++ /dev/null @@ -1,89 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.ui - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -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.tooling.preview.Preview -import com.tangem.core.ui.decorations.roundedShapeItemDecoration -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.core.ui.res.TangemTheme -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.common.ui.components.NetworkItem -import com.tangem.managetokens.presentation.addcustomtoken.state.ChooseNetworkState -import com.tangem.managetokens.presentation.addcustomtoken.state.previewdata.ChooseNetworkCustomPreviewData - -@Composable -internal fun ChooseNetworkCustomScreen(state: ChooseNetworkState, modifier: Modifier = Modifier) { - Column( - modifier = modifier - .fillMaxSize() - .background(color = TangemTheme.colors.background.tertiary) - .statusBarsPadding() - .navigationBarsPadding() - .padding( - top = TangemTheme.dimens.spacing10, - start = TangemTheme.dimens.spacing16, - end = TangemTheme.dimens.spacing16, - bottom = TangemTheme.dimens.spacing18, - ), - ) { - Box( - modifier = Modifier - .fillMaxWidth() - .defaultMinSize(minHeight = TangemTheme.dimens.size44) - .padding(bottom = TangemTheme.dimens.spacing12), - contentAlignment = Alignment.CenterStart, - ) { - Icon( - painter = painterResource(id = R.drawable.ic_back_24), - contentDescription = null, - tint = TangemTheme.colors.icon.primary1, - modifier = Modifier - .clickable { state.onCloseChoosingNetworkClick() }, - ) - Text( - text = stringResource(id = R.string.custom_token_network_selector_title), - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.subtitle1, - modifier = Modifier - .padding(horizontal = TangemTheme.dimens.spacing24) - .align(Alignment.Center), - ) - } - LazyColumn( - contentPadding = PaddingValues(vertical = TangemTheme.dimens.spacing12), - ) { - items(state.networks.count()) { index -> - NetworkItem( - state = state.networks[index], - tokenState = null, - isSelected = state.selectedNetwork == state.networks[index], - modifier = Modifier - .roundedShapeItemDecoration( - currentIndex = index, - lastIndex = state.networks.lastIndex, - addDefaultPadding = false, - ), - ) - } - } - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun Preview_ChooseNetworkScreen() { - TangemThemePreview { - ChooseNetworkCustomScreen(ChooseNetworkCustomPreviewData.state) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/CustomDerivationDialog.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/CustomDerivationDialog.kt deleted file mode 100644 index 969d7f61fb..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/CustomDerivationDialog.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.ui - -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import com.tangem.core.ui.components.AdditionalTextInputDialogParams -import com.tangem.core.ui.components.DialogButton -import com.tangem.core.ui.components.TextInputDialog -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.addcustomtoken.state.EnterCustomDerivationState - -@Composable -internal fun CustomDerivationDialog(state: EnterCustomDerivationState) { - val confirmButton = DialogButton( - title = stringResource(id = R.string.common_ok), - enabled = state.confirmButtonEnabled, - onClick = state.onConfirmButtonClick, - ) - - val dismissButton = DialogButton( - title = stringResource(id = R.string.common_cancel), - onClick = state.onDismiss, - ) - - val params = AdditionalTextInputDialogParams( - placeholder = stringResource(id = R.string.custom_token_custom_derivation_placeholder), - isError = state.derivationIncorrect, - errorText = if (state.derivationIncorrect) { - stringResource(R.string.custom_token_invalid_derivation_path) - } else { - null - }, - ) - - TextInputDialog( - fieldValue = state.value, - confirmButton = confirmButton, - onDismissDialog = state.onDismiss, - onValueChange = state.onValueChange, - textFieldParams = params, - title = stringResource(id = R.string.custom_token_custom_derivation_title), - dismissButton = dismissButton, - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/CustomTokenChooseWalletScreen.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/CustomTokenChooseWalletScreen.kt deleted file mode 100644 index 3b8eb7c2af..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/CustomTokenChooseWalletScreen.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.ui - -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.foundation.layout.statusBarsPadding -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import com.tangem.managetokens.presentation.common.state.ChooseWalletState -import com.tangem.managetokens.presentation.common.ui.ChooseWalletScreen - -@Composable -internal fun CustomTokensChooseWalletScreen(state: ChooseWalletState.Choose) { - ChooseWalletScreen( - state = state, - modifier = Modifier - .fillMaxSize() - .statusBarsPadding() - .navigationBarsPadding(), - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/TokenTextField.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/TokenTextField.kt deleted file mode 100644 index 63521c6775..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/ui/TokenTextField.kt +++ /dev/null @@ -1,81 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.ui - -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.text.BasicTextField -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.onFocusChanged -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.input.key.* -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.input.KeyboardType -import com.tangem.core.ui.res.TangemTheme -import com.tangem.managetokens.presentation.addcustomtoken.state.TextFieldState - -@Composable -internal fun TokenTextField( - state: TextFieldState.Editable, - placeholder: String, - onImeAction: () -> Unit, - keyboardOptions: KeyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Text, - imeAction = ImeAction.Default, - ), -) { - val isInitiallyComposed = remember { mutableStateOf(false) } - LaunchedEffect(key1 = true) { - isInitiallyComposed.value = true - } - - BasicTextField( - value = state.value, - onValueChange = state.onValueChange, - keyboardOptions = keyboardOptions, - singleLine = true, - maxLines = 1, - textStyle = TangemTheme.typography.subtitle1.copy( - fontWeight = FontWeight.Normal, - color = if (state.isEnabled) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.disabled, - ), - cursorBrush = SolidColor(TangemTheme.colors.icon.primary1), - modifier = Modifier - .fillMaxWidth() - .onKeyEvent { keyEvent -> - if (keyEvent.type == KeyEventType.KeyUp && keyEvent.key == Key.Enter) { - onImeAction() - true - } else { - false - } - } - .onFocusChanged { - if (!it.isFocused && isInitiallyComposed.value) { - state.onFocusExit() - } - }, - decorationBox = { innerTextField -> - Row(modifier = Modifier.fillMaxWidth()) { - if (state.value.isEmpty()) { - Text( - text = placeholder, - color = if (state.isEnabled) { - TangemTheme.colors.text.tertiary - } else { - TangemTheme.colors.text.disabled - }, - style = TangemTheme.typography.body2, - ) - } - } - innerTextField() - }, - enabled = state.isEnabled, - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/viewmodels/AddCustomTokenClickIntents.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/viewmodels/AddCustomTokenClickIntents.kt deleted file mode 100644 index 5a2e8e299b..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/viewmodels/AddCustomTokenClickIntents.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.viewmodels - -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import com.tangem.managetokens.presentation.addcustomtoken.state.Derivation - -@Suppress("TooManyFunctions") -internal interface AddCustomTokenClickIntents { - - fun onNetworkSelected(networkItemState: NetworkItemState) - - fun onChooseNetworkClick() - - fun onCloseChoosingNetworkClick() - - fun onWalletSelected(walletId: String) - - fun onChooseWalletClick() - - fun onCloseChoosingWalletClick() - - fun onContractAddressChange(input: String) - - fun onTokenNameChange(input: String) - - fun onSymbolChange(input: String) - - fun onDecimalsChange(input: String) - - fun onContractAddressFocusExit() - - fun onTokenNameFocusExit() - - fun onSymbolFocusExit() - - fun onDecimalsFocusExit() - - fun onDerivationSelected(derivation: Derivation) - - fun onChooseDerivationClick() - - fun onCloseChoosingDerivationClick() - - fun onEnterCustomDerivation() - - fun onCustomDerivationChange(input: String) - - fun onCustomDerivationSelected() - - fun onCustomDerivationDialogDismissed() - - fun onAddCustomButtonClick() - - fun onBack() -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/viewmodels/AddCustomTokenViewModel.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/viewmodels/AddCustomTokenViewModel.kt deleted file mode 100644 index 44e55b947d..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/addcustomtoken/viewmodels/AddCustomTokenViewModel.kt +++ /dev/null @@ -1,484 +0,0 @@ -package com.tangem.managetokens.presentation.addcustomtoken.viewmodels - -import androidx.compose.runtime.Stable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import arrow.core.getOrElse -import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.domain.common.util.derivationStyleProvider -import com.tangem.domain.tokens.* -import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.domain.tokens.model.Network -import com.tangem.domain.wallets.models.UserWallet -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase -import com.tangem.domain.wallets.usecase.GetWalletsUseCase -import com.tangem.domain.wallets.usecase.SelectWalletUseCase -import com.tangem.managetokens.presentation.addcustomtoken.router.AddCustomTokenRouter -import com.tangem.managetokens.presentation.common.analytics.ManageTokens -import com.tangem.managetokens.presentation.common.state.AlertState -import com.tangem.managetokens.presentation.common.state.Event -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import com.tangem.managetokens.presentation.addcustomtoken.state.* -import com.tangem.managetokens.presentation.addcustomtoken.state.factory.AddCustomTokenStateToCryptoCurrencyConverter -import com.tangem.managetokens.presentation.addcustomtoken.state.factory.ContractAddressToCustomTokenDataConverter -import com.tangem.managetokens.presentation.addcustomtoken.state.factory.AddCustomTokenStateFactory -import com.tangem.managetokens.presentation.addcustomtoken.state.factory.FoundTokenToCustomTokenDataConverter -import com.tangem.utils.Provider -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import com.tangem.utils.coroutines.Debouncer -import com.tangem.utils.coroutines.Debouncer.Companion.DEFAULT_WAIT_TIME_MS -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.collections.immutable.toPersistentSet -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.distinctUntilChanged -import javax.inject.Inject -import kotlin.properties.Delegates - -@Suppress("LongParameterList", "TooManyFunctions", "LargeClass") -@Stable -@HiltViewModel -internal class AddCustomTokenViewModel @Inject constructor( - private val dispatchers: CoroutineDispatcherProvider, - private val getWalletsUseCase: GetWalletsUseCase, - private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, - private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase, - private val selectWalletUseCase: SelectWalletUseCase, - private val getCurrenciesUseCase: GetCryptoCurrenciesUseCase, - private val findTokenByContractAddressUseCase: FindTokenByContractAddressUseCase, - private val validateContractAddressUseCase: ValidateContractAddressUseCase, - private val getNetworksSupportedByWallet: GetNetworksSupportedByWallet, - private val areTokensSupportedByNetworkUseCase: AreTokensSupportedByNetworkUseCase, - private val requiresHardenedDerivationOnlyUseCase: RequiresHardenedDerivationOnlyUseCase, - private val analyticsEventHandler: AnalyticsEventHandler, -) : ViewModel(), AddCustomTokenClickIntents, DefaultLifecycleObserver { - - private val debouncer = Debouncer() - - private val stateFactory = AddCustomTokenStateFactory( - currentStateProvider = Provider { uiState }, - clickIntents = this, - ) - - var router: AddCustomTokenRouter by Delegates.notNull() - - var uiState: AddCustomTokenState by mutableStateOf(stateFactory.getInitialState()) - private set - - /** - * Called when the bottom sheet was opened - */ - fun onInitialize() { - viewModelScope.launch(dispatchers.io) { - getWalletsUseCase() - .distinctUntilChanged() - .collectLatest { userWallets -> - val suitableUserWallets = userWallets.filter { it.isMultiCurrency && !it.isLocked } - val selectedWalletId = selectSuitableWallet(suitableUserWallets) - val networks = selectedWalletId?.let { getSupportedNetworks(selectedWalletId) } ?: emptyList() - withContext(dispatchers.main) { - uiState = stateFactory.getFullState( - allUserWallets = suitableUserWallets, - suitableUserWallets = userWallets, - selectedWalletId = selectedWalletId, - supportedNetworks = networks, - ) - } - } - } - } - - /** - * Called after the bottom sheet is closed - */ - fun onDispose() { - // We have to manually cancel viewModelScope's child jobs when bottom sheet is closed - viewModelScope.coroutineContext.cancelChildren() - // and reset state - uiState = stateFactory.getInitialState() - } - - private suspend fun selectSuitableWallet(suitableUserWallets: List): UserWalletId? { - val selectedWallet = getSelectedWalletSyncUseCase().getOrNull() - val selectedWalletId = if (walletSupportsAddingTokens(selectedWallet) && suitableUserWallets.isNotEmpty()) { - val walletId = suitableUserWallets.first().walletId - selectWalletUseCase(walletId) - walletId - } else { - selectedWallet?.walletId - } - return selectedWalletId - } - - private fun walletSupportsAddingTokens(userWallet: UserWallet?): Boolean { - return userWallet != null && userWallet.isMultiCurrency && !userWallet.isLocked - } - - private suspend fun getSupportedNetworks(userWalletId: UserWalletId): List { - return getNetworksSupportedByWallet(userWalletId).fold( - ifLeft = { emptyList() }, - ifRight = { it }, - ) - } - - override fun onNetworkSelected(networkItemState: NetworkItemState) { - analyticsEventHandler.send(ManageTokens.CustomTokenNetworkSelected(networkItemState.name)) - selectNetwork(networkItemState) - router.popBackStack() - } - - private fun selectNetwork(networkItemState: NetworkItemState) { - viewModelScope.launch(dispatchers.io) { - // TODO [REDACTED_TASK_KEY] - val selectedWalletId = getSelectedWalletSyncUseCase().getOrNull()?.walletId ?: return@launch - val supportsTokens = areTokensSupportedByNetworkUseCase( - networkId = networkItemState.id, - userWalletId = selectedWalletId, - ).getOrNull() ?: false - - val networksForDerivations = getSupportedNetworks(selectedWalletId) - - withContext(dispatchers.main) { - uiState = stateFactory.updateStateOnNetworkSelected( - networkItemState = networkItemState, - supportsTokens = supportsTokens, - networks = networksForDerivations, - requiresHardenedDerivationOnly = requiresHardenedDerivationOnly( - networkId = networkItemState.id, - userWalletId = selectedWalletId, - ), - ) - } - } - } - - override fun onChooseNetworkClick() { - router.openCustomTokenChooseNetwork() - } - - override fun onCloseChoosingNetworkClick() { - router.popBackStack() - } - - override fun onWalletSelected(walletId: String) { - analyticsEventHandler.send(ManageTokens.WalletSelected(ManageTokens.WalletSelected.Source.CustomToken)) - viewModelScope.launch(dispatchers.io) { - val userWalletId = UserWalletId(walletId) - selectWalletUseCase(userWalletId) - val supportedNetworks = getSupportedNetworks(UserWalletId(walletId)) - - withContext(dispatchers.main) { - uiState = stateFactory.updateWithNewWalletSelected( - selectedWalletId = userWalletId, - supportedNetworks = supportedNetworks, - ) - router.popBackStack() - } - } - } - - override fun onChooseWalletClick() { - router.openCustomTokenChooseWallet() - } - - override fun onCloseChoosingWalletClick() { - router.popBackStack() - } - - override fun onContractAddressChange(input: String) { - uiState = uiState.copy( - tokenData = uiState.tokenData?.copy( - contractAddressTextField = TextFieldState.Editable( - value = input, - isEnabled = true, - onValueChange = this::onContractAddressChange, - onFocusExit = this::onContractAddressFocusExit, - ), - ), - ) - debouncer.debounce(waitMs = DEFAULT_WAIT_TIME_MS, coroutineScope = viewModelScope + dispatchers.io) { - uiState.chooseNetworkState.selectedNetwork?.let { networkItemState -> - validateContractAddressUseCase(input, networkItemState.id).fold( - ifRight = { - uiState = stateFactory.removeTokenAddressError() - .copy( - addTokenButton = uiState.addTokenButton.copy( - isEnabled = uiState.tokenData?.isRequiredInformationProvided() == true, - ), - warnings = uiState.warnings - .filterNot { it is AddCustomTokenWarning.PotentialScamToken }.toPersistentSet(), - ) - fetchTokenInformation(contractAddress = input, networkId = networkItemState.id) - }, - ifLeft = { error -> - uiState = stateFactory.handleAddressError(error) - }, - ) - } - } - } - - private fun fetchTokenInformation(contractAddress: String, networkId: String) { - viewModelScope.launch(dispatchers.main) { - uiState = stateFactory.updateStateOnLoadingTokenInfo(contractAddress) - withContext(dispatchers.io) { - findTokenByContractAddressUseCase( - contractAddress = contractAddress, - networkId = networkId, - ).fold( - ifLeft = { - val tokenData = ContractAddressToCustomTokenDataConverter(this@AddCustomTokenViewModel) - .convert(contractAddress) - - val isButtonEnabled = tokenData.isRequiredInformationProvided() - uiState = uiState.copy( - tokenData = tokenData, - warnings = (uiState.warnings + AddCustomTokenWarning.PotentialScamToken).toPersistentSet(), - addTokenButton = uiState.addTokenButton.copy( - isEnabled = isButtonEnabled, - ), - ) - }, - ifRight = { token -> - val tokenData = if (token != null) { - FoundTokenToCustomTokenDataConverter(this@AddCustomTokenViewModel).convert(token) - } else { - ContractAddressToCustomTokenDataConverter(this@AddCustomTokenViewModel).convert( - contractAddress, - ) - } - - val isButtonEnabled = tokenData.isRequiredInformationProvided() - uiState = uiState.copy( - tokenData = tokenData, - addTokenButton = uiState.addTokenButton.copy( - isEnabled = isButtonEnabled, - ), - ) - }, - ) - } - } - } - - override fun onTokenNameChange(input: String) { - uiState = uiState.copy( - tokenData = uiState.tokenData?.copy( - nameTextField = TextFieldState.Editable( - value = input, - isEnabled = true, - onValueChange = this::onTokenNameChange, - onFocusExit = this::onTokenNameFocusExit, - ), - ), - addTokenButton = uiState.addTokenButton.copy( - isEnabled = uiState.tokenData?.isRequiredInformationProvided() == true, - ), - ) - } - - override fun onSymbolChange(input: String) { - uiState = uiState.copy( - tokenData = uiState.tokenData?.copy( - symbolTextField = TextFieldState.Editable( - value = input, - isEnabled = true, - onValueChange = this::onSymbolChange, - onFocusExit = this::onSymbolFocusExit, - ), - ), - addTokenButton = uiState.addTokenButton.copy( - isEnabled = uiState.tokenData?.isRequiredInformationProvided() == true, - ), - ) - } - - override fun onDecimalsChange(input: String) { - val correctInput = input.toIntOrNull() - val error = if (input.isNotBlank() && correctInput == null) { - AddCustomTokenWarning.WrongDecimals - } else { - null - } - uiState = uiState.copy( - tokenData = uiState.tokenData?.copy( - decimalsTextField = TextFieldState.Editable( - value = input, - isEnabled = true, - onValueChange = this::onDecimalsChange, - error = error, - onFocusExit = this::onDecimalsFocusExit, - ), - ), - addTokenButton = uiState.addTokenButton.copy( - isEnabled = uiState.tokenData?.isRequiredInformationProvided() == true, - ), - ) - } - - override fun onContractAddressFocusExit() { - val error = (uiState.tokenData?.contractAddressTextField as? TextFieldState.Editable)?.error - val validated = error !is AddCustomTokenWarning.InvalidContractAddress - analyticsEventHandler.send(ManageTokens.CustomTokenAddress(validated = validated)) - } - - override fun onTokenNameFocusExit() { - analyticsEventHandler.send(ManageTokens.CustomTokenName) - } - - override fun onSymbolFocusExit() { - analyticsEventHandler.send(ManageTokens.CustomTokenSymbol) - } - - override fun onDecimalsFocusExit() { - analyticsEventHandler.send(ManageTokens.CustomTokenDecimals) - } - - override fun onDerivationSelected(derivation: Derivation) { - derivation.standardType?.let { - analyticsEventHandler.send(ManageTokens.CustomTokenDerivationSelected(derivation.networkName)) - } - uiState = uiState.copy( - chooseDerivationState = uiState.chooseDerivationState?.copy(selectedDerivation = derivation), - ) - router.popBackStack() - } - - override fun onChooseDerivationClick() { - router.openCustomTokenChooseDerivation() - } - - override fun onCloseChoosingDerivationClick() { - router.popBackStack() - } - - override fun onCustomDerivationChange(input: String) { - val selectedWallet = getSelectedWalletSyncUseCase().getOrNull() ?: return - - analyticsEventHandler.send(ManageTokens.CustomTokenDerivationSelected(ManageTokens.Derivation.CUSTOM.value)) - uiState = uiState.copy( - chooseDerivationState = uiState.chooseDerivationState?.copy( - enterCustomDerivationState = uiState.chooseDerivationState?.enterCustomDerivationState?.copy( - value = input, - ), - ), - ) - debouncer.debounce(waitMs = DEFAULT_WAIT_TIME_MS, coroutineScope = viewModelScope + dispatchers.io) { - val networkId = uiState.chooseNetworkState.selectedNetwork?.id ?: return@debounce - uiState = stateFactory.updateOnCustomDerivationEntered( - input = input, - requiresHardenedDerivationOnly = requiresHardenedDerivationOnly(networkId, selectedWallet.walletId), - ) - } - } - - private suspend fun requiresHardenedDerivationOnly(networkId: String, userWalletId: UserWalletId): Boolean { - return requiresHardenedDerivationOnlyUseCase.invoke( - networkId = networkId, - userWalletId = userWalletId, - ).getOrElse { false } - } - - override fun onCustomDerivationSelected() { - uiState = stateFactory.updateOnCustomDerivationSelected() - router.popBackStack() - } - - override fun onEnterCustomDerivation() { - uiState = stateFactory.updateStateOnEnterCustomDerivation() - } - - override fun onCustomDerivationDialogDismissed() { - uiState = uiState.copy( - chooseDerivationState = uiState.chooseDerivationState?.copy( - enterCustomDerivationState = null, - ), - ) - } - - override fun onAddCustomButtonClick() { - viewModelScope.launch(dispatchers.io) { - val selectedWallet = getSelectedWalletSyncUseCase().getOrNull() ?: return@launch - val cryptoCurrency = AddCustomTokenStateToCryptoCurrencyConverter( - selectedWallet.scanResponse.derivationStyleProvider, - ).convert(uiState) - val alreadyAdded = isCryptoCurrencyAlreadyAdded(selectedWallet, cryptoCurrency) - if (alreadyAdded) { - uiState = stateFactory.getStateAndTriggerEvent( - state = uiState, - event = Event.ShowAlert(AlertState.TokenAlreadyAdded), - setUiState = { uiState = it }, - ) - } else { - sendTokenAddedEvent(cryptoCurrency) - addCryptoCurrenciesUseCase(selectedWallet.walletId, currency = cryptoCurrency) - withContext(dispatchers.main) { router.popBackStack() } - } - } - } - - private suspend fun isCryptoCurrencyAlreadyAdded( - selectedWallet: UserWallet, - cryptoCurrency: CryptoCurrency, - ): Boolean { - val currenciesList = getCurrenciesUseCase.getSync(selectedWallet.walletId).getOrElse { emptyList() } - return when (cryptoCurrency) { - is CryptoCurrency.Coin -> { - currenciesList.any { - it is CryptoCurrency.Coin && - it.id == cryptoCurrency.id && - it.network.derivationPath == cryptoCurrency.network.derivationPath - } - } - is CryptoCurrency.Token -> { - currenciesList.any { - (it as? CryptoCurrency.Token)?.let { - it.id == cryptoCurrency.id && - it.contractAddress == cryptoCurrency.contractAddress && - it.network.id == cryptoCurrency.network.id && - it.network.derivationPath == cryptoCurrency.network.derivationPath - } ?: false - } - } - } - } - - private fun sendTokenAddedEvent(cryptoCurrency: CryptoCurrency) { - val selectedDerivation = uiState.chooseDerivationState?.selectedDerivation - - val derivation = when { - selectedDerivation == null -> ManageTokens.Derivation.DEFAULT.value - selectedDerivation.networkName.isNotEmpty() -> selectedDerivation.networkName - else -> ManageTokens.Derivation.CUSTOM.value - } - when (cryptoCurrency) { - is CryptoCurrency.Token -> { - analyticsEventHandler.send( - ManageTokens.CustomTokenWasAdded( - derivation = derivation, - networkId = cryptoCurrency.network.name, - contractAddress = cryptoCurrency.contractAddress, - token = cryptoCurrency.symbol, - ), - ) - } - is CryptoCurrency.Coin -> { - analyticsEventHandler.send( - ManageTokens.CustomTokenWasAdded( - derivation = derivation, - networkId = cryptoCurrency.network.name, - ), - ) - } - } - } - - override fun onBack() { - router.popBackStack() - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/analytics/ManageTokens.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/analytics/ManageTokens.kt deleted file mode 100644 index 3a527de7f2..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/analytics/ManageTokens.kt +++ /dev/null @@ -1,102 +0,0 @@ -package com.tangem.managetokens.presentation.common.analytics - -import com.tangem.core.analytics.models.AnalyticsEvent -import com.tangem.core.analytics.models.AnalyticsParam - -sealed class ManageTokens( - event: String, - params: Map = emptyMap(), -) : AnalyticsEvent("Manage Tokens", event, params) { - - class ScreenOpened : ManageTokens("Manage Tokens Screen Opened") - - class TokenIsNotFound(userInput: String) : ManageTokens( - event = "Token Is Not Found", - params = mapOf("Input" to userInput), - ) - - class TokenSwitcherChanged( - token: String, - state: AnalyticsParam.OnOffState, - ) : ManageTokens( - event = "Token Switcher Changed", - params = mapOf( - "Token" to token, - "State" to state.value, - ), - ) - - class ButtonAdd(token: String) : ManageTokens( - event = "Button - Add", - params = mapOf("Token" to token), - ) - - class ButtonEdit(token: String) : ManageTokens( - event = "Button - Edit", - params = mapOf("Token" to token), - ) - - object ButtonChooseWallet : ManageTokens(event = "Button - Choose Wallet") - - class WalletSelected(source: Source) : ManageTokens( - event = "Wallet Selected", - params = mapOf("Source" to source.name), - ) { - - enum class Source(name: String) { - MainToken("Main Token"), - CustomToken("Custom Token"), - } - } - - object NoticeNonNativeNetworkClicked : ManageTokens(event = "Notice - Non Native Network Clicked") - - class ButtonGenerateAddresses(cardCount: Int) : ManageTokens( - event = "Button - Get Addresses", - params = mapOf("CardCount" to cardCount.toString()), - ) - - object ButtonCustomToken : ManageTokens("Button - Custom Token") - - class CustomTokenWasAdded( - val derivation: String, - val networkId: String, - val token: String? = null, - val contractAddress: String? = null, - ) : ManageTokens( - event = "Custom Token Was Added", - params = mutableMapOf( - "Derivation" to derivation, - "Network Id" to networkId, - ).apply { - token?.let { put("Token", it) } - contractAddress?.let { put("Contract Address", it) } - }, - ) - - class CustomTokenNetworkSelected(blockchain: String) : ManageTokens( - event = "Custom Token Network Selected", - params = mapOf("blockchain" to blockchain), - ) - - class CustomTokenDerivationSelected(derivation: String) : ManageTokens( - event = "Custom Token Derivation Selected", - params = mapOf("Derivation" to derivation), - ) - - class CustomTokenAddress(validated: Boolean) : ManageTokens( - "Custom Token Address", - params = mapOf("Validation" to if (validated) "Ok" else "Error"), - ) - - object CustomTokenName : ManageTokens("Custom Token Name") - - object CustomTokenSymbol : ManageTokens("Custom Token Symbol") - - object CustomTokenDecimals : ManageTokens("Custom Token Decimals") - - enum class Derivation(val value: String) { - DEFAULT("Default"), - CUSTOM("Custom"), - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/AlertState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/AlertState.kt deleted file mode 100644 index 82ba359079..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/AlertState.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.tangem.managetokens.presentation.common.state - -import com.tangem.core.ui.extensions.TextReference -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.wrappedList -import com.tangem.features.managetokens.impl.R - -internal sealed class AlertState { - - abstract val message: TextReference - - class DefaultAlert( - override val message: TextReference, - ) : AlertState() - - class TokenUnavailable( - val onUpvoteClick: () -> Unit, - ) : AlertState() { - override val message: TextReference = resourceReference(R.string.manage_tokens_unavailable_description) - val confirmButtonText: TextReference = resourceReference(R.string.common_close) - val dismissButtonText: TextReference = resourceReference(R.string.manage_tokens_unavailable_vote) - } - - object NonNative : AlertState() { - override val message: TextReference = resourceReference(R.string.manage_tokens_network_selector_non_native_info) - } - - class TokensUnsupported(networkName: String) : AlertState() { - override val message: TextReference = resourceReference( - id = R.string.alert_manage_tokens_unsupported_message, - formatArgs = wrappedList(networkName), - ) - } - - object TokensUnsupportedCurve : AlertState() { - override val message: TextReference = resourceReference(R.string.alert_manage_tokens_unsupported_curve_message) - } - - class TokensUnsupportedBlockchainByCard(networkName: String) : AlertState() { - override val message: TextReference = resourceReference( - id = R.string.alert_manage_tokens_unsupported_blockchain_by_card_message, - formatArgs = wrappedList(networkName), - ) - } - - class CannotHideNetworkWithTokens(tokenName: String, currencySymbol: String, networkName: String) : AlertState() { - override val message: TextReference = resourceReference( - id = R.string.token_details_unable_hide_alert_message, - formatArgs = wrappedList(tokenName, currencySymbol, networkName), - ) - } - - object TokenAlreadyAdded : AlertState() { - override val message: TextReference = resourceReference(R.string.custom_token_validation_error_already_added) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/ChooseWalletState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/ChooseWalletState.kt deleted file mode 100644 index 6a585d7148..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/ChooseWalletState.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.tangem.managetokens.presentation.common.state - -import com.tangem.core.ui.extensions.TextReference -import com.tangem.features.managetokens.impl.R -import kotlinx.collections.immutable.ImmutableList - -internal sealed class ChooseWalletState { - data class Choose( - val wallets: ImmutableList, - val selectedWallet: WalletState?, - val onChooseWalletClick: () -> Unit, - val onCloseChoosingWalletClick: () -> Unit, - val show: Boolean = false, - ) : ChooseWalletState() - - object NoSelection : ChooseWalletState() - - class Warning(val type: ChooseWalletWarning) : ChooseWalletState() { - val message: TextReference - get() = when (type) { - ChooseWalletWarning.SINGLE_CURRENCY -> - TextReference.Res(R.string.manage_tokens_wallet_support_only_one_network_title) - } - } -} - -enum class ChooseWalletWarning { - SINGLE_CURRENCY, -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/Event.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/Event.kt deleted file mode 100644 index 4024d7a4d8..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/Event.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.managetokens.presentation.common.state - -import androidx.compose.runtime.Immutable - -@Immutable -internal sealed interface Event { - data class ShowAlert(val state: AlertState) : Event -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/NetworkItemState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/NetworkItemState.kt deleted file mode 100644 index 6255c750f9..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/NetworkItemState.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.tangem.managetokens.presentation.common.state - -import androidx.compose.runtime.MutableState -import com.tangem.core.ui.extensions.* -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState - -/** - * Network item state - * - * @property name network name - * @property protocolName network protocol name - * @property id network id - * @property iconRes network icon id from resources - */ -internal sealed interface NetworkItemState { - - val name: String - val protocolName: String - val id: String - - val iconRes: Int - get() = when (this) { - is Selectable -> this.iconResId - is Toggleable -> this.iconResId.value - } - - /** - * Network item state that can be added and deleted - * - * @property name network name - * @property protocolName network protocol name - * @property id network id - * @property iconResId network icon id from resources - * @property isMainNetwork flag that determines if the network is the main network for the token - * @property isAdded flag that determines if the user has saved the network - * @property address contract address - * @property decimals decimal count - * @property onToggleClick lambda be invoked when switch is been toggled - */ - @Suppress("LongParameterList") - data class Toggleable( - override val name: String, - override val protocolName: String, - override val id: String, - val iconResId: MutableState, - val isMainNetwork: Boolean, - val isAdded: MutableState, - val address: String?, - val decimals: Int?, - val onToggleClick: (TokenItemState.Loaded, Toggleable) -> Unit, - ) : NetworkItemState { - - /** - * Change toggle state [isAdded]. - * - * It is a hack that helps us to change element of flow - */ - fun changeToggleState() { - val reverseState = !isAdded.value - isAdded.value = reverseState - iconResId.value = if (reverseState) getActiveIconResByNetworkId(id) else getGreyedOutIconResByNetworkId(id) - } - } - - /** - * Network item state that can be selected - * - * @property name network name - * @property protocolName network protocol name - * @property iconResId network icon id from resources - * @property id network id - * @property onNetworkClick lambda be invoked when network item is been clicked - * - */ - data class Selectable( - override val name: String, - override val protocolName: String, - val iconResId: Int, - override val id: String, - val onNetworkClick: (NetworkItemState) -> Unit, - ) : NetworkItemState -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/WalletState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/WalletState.kt deleted file mode 100644 index 6af48736a4..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/WalletState.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.managetokens.presentation.common.state - -internal data class WalletState( - val walletId: String, - val artworkUrl: String?, - val walletName: String, - val onSelected: (String) -> Unit, -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/previewdata/ChooseWalletStatePreviewData.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/previewdata/ChooseWalletStatePreviewData.kt deleted file mode 100644 index f231654b96..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/state/previewdata/ChooseWalletStatePreviewData.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.tangem.managetokens.presentation.common.state.previewdata - -import com.tangem.managetokens.presentation.common.state.ChooseWalletState -import com.tangem.managetokens.presentation.common.state.WalletState -import kotlinx.collections.immutable.persistentListOf - -internal object ChooseWalletStatePreviewData { - - val state: ChooseWalletState.Choose - get() = ChooseWalletState.Choose( - wallets = persistentListOf( - walletState, - walletState.copy(walletId = "2"), - ), - selectedWallet = walletState, - onChooseWalletClick = {}, - onCloseChoosingWalletClick = {}, - ) - - private val walletState: WalletState - get() = WalletState( - walletName = "My wallet", - walletId = "1", - artworkUrl = "", - onSelected = {}, - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/ChooseWalletBottomSheet.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/ChooseWalletBottomSheet.kt deleted file mode 100644 index 9bf85280d4..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/ChooseWalletBottomSheet.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.tangem.managetokens.presentation.common.ui - -import androidx.compose.runtime.Composable -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent -import com.tangem.core.ui.res.TangemTheme -import com.tangem.managetokens.presentation.common.state.ChooseWalletState - -@Composable -internal fun ChooseWalletBottomSheet(config: TangemBottomSheetConfig) { - TangemBottomSheet( - config = config, - containerColor = TangemTheme.colors.background.tertiary, - ) { - ChooseWalletScreen(state = it.chooseWalletState) - } -} - -internal class ChooseWalletBottomSheetConfig( - val chooseWalletState: ChooseWalletState.Choose, -) : TangemBottomSheetConfigContent \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/ChooseWalletScreen.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/ChooseWalletScreen.kt deleted file mode 100644 index 121faaba26..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/ChooseWalletScreen.kt +++ /dev/null @@ -1,150 +0,0 @@ -package com.tangem.managetokens.presentation.common.ui - -import android.content.res.Configuration -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -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 coil.compose.SubcomposeAsyncImage -import coil.request.ImageRequest -import com.tangem.core.ui.components.SpacerH -import com.tangem.core.ui.components.SpacerW12 -import com.tangem.core.ui.components.SpacerWMax -import com.tangem.core.ui.decorations.roundedShapeItemDecoration -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.common.state.ChooseWalletState -import com.tangem.managetokens.presentation.common.state.WalletState -import com.tangem.managetokens.presentation.common.state.previewdata.ChooseWalletStatePreviewData - -@Composable -internal fun ChooseWalletScreen(state: ChooseWalletState.Choose, modifier: Modifier = Modifier) { - LazyColumn( - modifier = modifier - .background(TangemTheme.colors.background.tertiary) - .padding( - start = TangemTheme.dimens.spacing16, - end = TangemTheme.dimens.spacing16, - bottom = TangemTheme.dimens.spacing16, - ), - ) { - item { - Box( - modifier = Modifier.defaultMinSize(minHeight = TangemTheme.dimens.size44), - ) { - IconButton( - onClick = state.onCloseChoosingWalletClick, - modifier = Modifier - .align(Alignment.CenterStart) - .clickable { state.onCloseChoosingWalletClick() }, - ) { - Icon( - painterResource(id = R.drawable.ic_back_24), - contentDescription = null, - tint = TangemTheme.colors.icon.primary1, - ) - } - Text( - text = stringResource(id = R.string.manage_tokens_wallet_selector_title), - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.subtitle1, - textAlign = TextAlign.Center, - maxLines = 1, - modifier = Modifier - .fillMaxWidth() - .align(Alignment.Center), - ) - } - } - items( - count = state.wallets.count(), - key = { index -> state.wallets[index].walletId }, - ) { index -> - WalletItem( - wallet = state.wallets[index], - selectedWallet = state.selectedWallet, - modifier = Modifier - .roundedShapeItemDecoration( - currentIndex = index, - lastIndex = state.wallets.lastIndex, - addDefaultPadding = false, - ), - ) - } - item { - SpacerH(height = TangemTheme.dimens.spacing16) - } - } -} - -@Composable -private fun WalletItem(wallet: WalletState, selectedWallet: WalletState?, modifier: Modifier = Modifier) { - Row( - modifier = modifier - .clickable { wallet.onSelected(wallet.walletId) } - .background(TangemTheme.colors.background.action) - .defaultMinSize(minHeight = TangemTheme.dimens.size72) - .padding(horizontal = TangemTheme.dimens.spacing16), - verticalAlignment = Alignment.CenterVertically, - ) { - SubcomposeAsyncImage( - modifier = Modifier.size(height = TangemTheme.dimens.size30, width = TangemTheme.dimens.size50), - - model = ImageRequest.Builder(context = LocalContext.current) - .data(wallet.artworkUrl) - .crossfade(enable = true) - .build(), - loading = { - Image( - painter = painterResource(R.drawable.card_placeholder_black), - contentDescription = null, - ) - }, - error = { - Image( - painter = painterResource(R.drawable.card_placeholder_black), - contentDescription = null, - ) - }, - contentDescription = null, - ) - SpacerW12() - Text( - text = wallet.walletName, - style = TangemTheme.typography.subtitle1, - color = TangemTheme.colors.text.primary1, - ) - SpacerWMax() - if (selectedWallet == wallet) { - Icon( - painter = painterResource(id = R.drawable.ic_check_24), - contentDescription = null, - tint = TangemTheme.colors.icon.accent, - ) - } - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun Preview_ChooseWalletScreen() { - TangemThemePreview { - ChooseWalletScreen( - state = ChooseWalletStatePreviewData.state, - ) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/EventEffect.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/EventEffect.kt deleted file mode 100644 index 0bfc404f35..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/EventEffect.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.managetokens.presentation.common.ui - -import androidx.compose.runtime.Composable -import com.tangem.core.ui.event.StateEvent -import com.tangem.managetokens.presentation.common.state.AlertState -import com.tangem.managetokens.presentation.common.state.Event - -@Composable -internal fun EventEffect(event: StateEvent, onAlertStateSet: (AlertState) -> Unit) { - com.tangem.core.ui.event.EventEffect( - event = event, - onTrigger = { value -> - when (value) { - is Event.ShowAlert -> onAlertStateSet(value.state) - } - }, - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/Alert.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/Alert.kt deleted file mode 100644 index 14e49a02b6..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/Alert.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.tangem.managetokens.presentation.common.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.core.ui.extensions.resolveReference -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.common.state.AlertState - -@Composable -internal fun Alert(state: AlertState, onDismiss: () -> Unit) { - when (state) { - is AlertState.DefaultAlert, - is AlertState.NonNative, - AlertState.TokensUnsupportedCurve, - is AlertState.TokensUnsupported, - is AlertState.TokensUnsupportedBlockchainByCard, - is AlertState.CannotHideNetworkWithTokens, - is AlertState.TokenAlreadyAdded, - -> DefaultAlert(state, onDismiss) - is AlertState.TokenUnavailable -> TokenUnavailableAlert(state, onDismiss) - } -} - -@Composable -private fun DefaultAlert(state: AlertState, onDismiss: () -> Unit) { - BasicDialog( - message = state.message.resolveReference(), - confirmButton = DialogButton( - title = stringResource(id = R.string.common_ok), - onClick = onDismiss, - ), - onDismissDialog = onDismiss, - ) -} - -@Composable -private fun TokenUnavailableAlert(state: AlertState.TokenUnavailable, onDismiss: () -> Unit) { - BasicDialog( - message = state.message.resolveReference(), - confirmButton = DialogButton( - title = state.confirmButtonText.resolveReference(), - onClick = onDismiss, - ), - dismissButton = DialogButton( - title = state.dismissButtonText.resolveReference(), - onClick = { state.onUpvoteClick() }, - ), - onDismissDialog = onDismiss, - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/NetworkItem.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/NetworkItem.kt deleted file mode 100644 index 553a6bd999..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/NetworkItem.kt +++ /dev/null @@ -1,167 +0,0 @@ -package com.tangem.managetokens.presentation.common.ui.components - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider -import com.tangem.core.ui.components.SpacerW -import com.tangem.core.ui.components.TangemSwitch -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.core.ui.res.TangemTheme -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState -import com.tangem.managetokens.presentation.managetokens.state.previewdata.TokenItemStatePreviewData - -@Composable -internal fun NetworkItem( - state: NetworkItemState, - tokenState: TokenItemState.Loaded?, - modifier: Modifier = Modifier, - isSelected: Boolean = false, -) { - Row( - modifier = modifier - .background(TangemTheme.colors.background.action) - .defaultMinSize(minHeight = TangemTheme.dimens.size68) - .then( - if (state is NetworkItemState.Selectable) { - Modifier.clickable { state.onNetworkClick(state) } - } else { - Modifier - }, - ) - .padding(horizontal = TangemTheme.dimens.spacing16) - .fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - ) { - NetworkIcon(model = state) - SpacerW(width = TangemTheme.dimens.spacing12) - Text( - text = state.name, - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.subtitle2, - ) - SpacerW(width = TangemTheme.dimens.spacing6) - Text( - text = state.protocolName, - color = TangemTheme.colors.text.tertiary, - style = TangemTheme.typography.body2, - modifier = Modifier - .weight(1f), - ) - if (state is NetworkItemState.Toggleable) { - TangemSwitch( - onCheckedChange = { - state.onToggleClick(tokenState!!, state) - }, - checked = state.isAdded.value, - ) - } else if (state is NetworkItemState.Selectable && isSelected) { - Icon( - painter = painterResource(id = R.drawable.ic_check_24), - contentDescription = null, - tint = TangemTheme.colors.icon.accent, - ) - } - } -} - -@Composable -internal fun NetworkIcon(model: NetworkItemState, modifier: Modifier = Modifier) { - Box(modifier = modifier.size(size = TangemTheme.dimens.size36)) { - val isAdded = when (model) { - is NetworkItemState.Selectable -> true - is NetworkItemState.Toggleable -> model.isAdded.value - } - - if (!isAdded) { - Box( - modifier = Modifier - .size(TangemTheme.dimens.size36) - .clip(CircleShape) - .background(TangemTheme.colors.control.unchecked), - ) - } - Icon( - painter = painterResource(id = model.iconRes), - contentDescription = null, - modifier = Modifier.size(size = TangemTheme.dimens.size36), - tint = if (isAdded) Color.Unspecified else TangemTheme.colors.text.tertiary, - ) - - if (model is NetworkItemState.Toggleable && model.isMainNetwork) { - Box( - modifier = Modifier - .align(Alignment.TopEnd) - .size(TangemTheme.dimens.size10) - .clip(CircleShape) - .background(TangemTheme.colors.stroke.transparency), - contentAlignment = Alignment.Center, - ) { - Box( - modifier = Modifier - .size(TangemTheme.dimens.size8) - .clip(CircleShape) - .background(TangemTheme.colors.icon.accent), - ) - } - } - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun Preview_NetworkItem(@PreviewParameter(NetworkItemStateProvider::class) state: NetworkItemState) { - TangemThemePreview { - NetworkItem(state, tokenState = TokenItemStatePreviewData.loadedPriceDown as TokenItemState.Loaded) - } -} - -private class NetworkItemStateProvider : CollectionPreviewParameterProvider( - collection = listOf( - NetworkItemState.Toggleable( - name = "Ethereum", - protocolName = "ETH", - iconResId = mutableStateOf(R.drawable.img_polygon_22), - isMainNetwork = true, - isAdded = mutableStateOf(true), - id = "", - address = "", - onToggleClick = { _, _ -> }, - decimals = 0, - ), - NetworkItemState.Toggleable( - name = "BNB SMART CHAIN", - protocolName = "BEP20", - iconResId = mutableStateOf(R.drawable.ic_bsc_16), - isMainNetwork = false, - isAdded = mutableStateOf(false), - id = "", - address = "", - onToggleClick = { _, _ -> }, - decimals = 0, - ), - NetworkItemState.Selectable( - name = "Ethereum", - protocolName = "ETH", - iconResId = R.drawable.img_polygon_22, - id = "", - onNetworkClick = { }, - ), - ), -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/SimpleSelectionBlock.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/SimpleSelectionBlock.kt deleted file mode 100644 index e7ad5cf31b..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/ui/components/SimpleSelectionBlock.kt +++ /dev/null @@ -1,65 +0,0 @@ -package com.tangem.managetokens.presentation.common.ui.components - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.SpacerH -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.core.ui.res.TangemTheme - -@Composable -fun SimpleSelectionBlock( - title: String, - subtitle: String, - onClick: () -> Unit, - modifier: Modifier = Modifier, - roundedCorners: Boolean = true, -) { - Column( - modifier = modifier - .then( - if (roundedCorners) { - Modifier.clip(shape = RoundedCornerShape(TangemTheme.dimens.radius16)) - } else { - Modifier - }, - ) - .background(color = TangemTheme.colors.background.action) - .clickable { onClick() } - .padding( - horizontal = TangemTheme.dimens.spacing20, - vertical = TangemTheme.dimens.spacing16, - ) - .fillMaxWidth(), - ) { - Text( - text = title, - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.subtitle1, - ) - SpacerH(height = TangemTheme.dimens.spacing4) - Text( - text = subtitle, - color = TangemTheme.colors.text.secondary, - style = TangemTheme.typography.body2, - ) - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun Preview_SimpleSelectionBlock() { - TangemThemePreview { - SimpleSelectionBlock(title = "Wallet", subtitle = "Family Wallet", onClick = { }) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/utils/CurrencyUtils.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/utils/CurrencyUtils.kt deleted file mode 100644 index b005f36dee..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/common/utils/CurrencyUtils.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.managetokens.presentation.common.utils - -import com.tangem.domain.tokens.model.CryptoCurrency - -internal object CurrencyUtils { - fun isAdded(address: String?, networkId: String, currencies: Collection): Boolean { - return if (address != null) { - currencies.any { - !it.isCustom && it is CryptoCurrency.Token && it.contractAddress == address && - it.network.backendId == networkId - } - } else { - currencies.any { - !it.isCustom && it is CryptoCurrency.Coin && it.network.backendId == networkId - } - } - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/ChooseNetworkState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/ChooseNetworkState.kt deleted file mode 100644 index df2a7f015f..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/ChooseNetworkState.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state - -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import kotlinx.collections.immutable.ImmutableList - -internal data class ChooseNetworkState( - val nativeNetworks: ImmutableList, - val nonNativeNetworks: ImmutableList, - val onNonNativeNetworkHintClick: () -> Unit, - val onCloseChooseNetworkScreen: () -> Unit, -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/DerivationNotificationState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/DerivationNotificationState.kt deleted file mode 100644 index 0cfdfa16d1..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/DerivationNotificationState.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state - -import com.tangem.core.ui.components.notifications.NotificationConfig -import com.tangem.core.ui.extensions.pluralReference -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.wrappedList -import com.tangem.features.managetokens.impl.R - -data class DerivationNotificationState( - val totalNeeded: Int, - val totalWallets: Int, - val walletsToDerive: Int, - val onGenerateClick: () -> Unit, -) { - val config = NotificationConfig( - title = resourceReference(id = R.string.warning_missing_derivation_title), - subtitle = pluralReference( - id = R.plurals.warning_missing_derivation_message, - count = totalNeeded, - formatArgs = wrappedList(totalNeeded), - ), - iconResId = R.drawable.ic_alert_circle_24, - buttonsState = NotificationConfig.ButtonsState.PrimaryButtonConfig( - text = resourceReference(id = R.string.common_generate_addresses), - iconResId = R.drawable.ic_tangem_24, - onClick = onGenerateClick, - additionalText = pluralReference( - id = R.plurals.manage_tokens_number_of_wallets_android, - count = totalWallets, - formatArgs = wrappedList(walletsToDerive, totalWallets), - ), - ), - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/ManageTokensState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/ManageTokensState.kt deleted file mode 100644 index 6738d56d3f..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/ManageTokensState.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state - -import androidx.paging.PagingData -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig -import com.tangem.core.ui.event.StateEvent -import com.tangem.managetokens.presentation.common.state.ChooseWalletState -import com.tangem.managetokens.presentation.common.state.Event -import kotlinx.coroutines.flow.Flow - -internal data class ManageTokensState( - val searchBarState: SearchBarState, - val tokens: Flow>, - val isLoading: Boolean, - val addCustomTokenButton: AddCustomTokenButton, - val chooseWalletState: ChooseWalletState, - val derivationNotification: DerivationNotificationState? = null, - val selectedToken: TokenItemState.Loaded? = null, - val showChooseWalletScreen: Boolean = false, - val customTokenBottomSheetConfig: TangemBottomSheetConfig, - val event: StateEvent, - val onEmptySearchResult: (String) -> Unit, -) - -data class AddCustomTokenButton( - val isVisible: Boolean, - val onClick: () -> Unit, -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/QuotesState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/QuotesState.kt deleted file mode 100644 index 3518626707..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/QuotesState.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state - -import com.tangem.core.ui.components.marketprice.PriceChangeType -import kotlinx.collections.immutable.ImmutableList - -internal sealed class QuotesState { - object Unknown : QuotesState() - - data class Content( - val priceChange: String, - val changeType: PriceChangeType, - val chartData: ImmutableList, - ) : QuotesState() -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/SearchBarState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/SearchBarState.kt deleted file mode 100644 index d64808239e..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/SearchBarState.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state - -/** - * SearchBar state. - */ -internal data class SearchBarState( - val query: String, - val onQueryChange: (String) -> Unit, - val active: Boolean, - val onActiveChange: (Boolean) -> Unit, -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenButtonType.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenButtonType.kt deleted file mode 100644 index 6c47a870ec..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenButtonType.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state - -internal enum class TokenButtonType { - ADD, EDIT, NOT_AVAILABLE -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenIconState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenIconState.kt deleted file mode 100644 index 0bd0c0d25d..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenIconState.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state - -import androidx.compose.ui.graphics.Color -import com.tangem.core.ui.extensions.ImageReference - -internal data class TokenIconState( - val iconReference: ImageReference?, - val placeholderTint: Color, - val placeholderBackground: Color, -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenItemState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenItemState.kt deleted file mode 100644 index 7262bbe337..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/TokenItemState.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state - -import androidx.compose.runtime.MutableState - -internal sealed class TokenItemState { - - abstract val id: String - - data class Loading(override val id: String) : TokenItemState() - - data class Loaded( - override val id: String, - val name: String, - val currencySymbol: String, - val tokenId: String, - val tokenIcon: TokenIconState, - val quotes: QuotesState, - val rate: String?, - val availableAction: MutableState, - val chooseNetworkState: ChooseNetworkState, - val onButtonClick: (Loaded) -> Unit, - ) : TokenItemState() -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/ManageTokensStateFactory.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/ManageTokensStateFactory.kt deleted file mode 100644 index d7531b2e85..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/ManageTokensStateFactory.kt +++ /dev/null @@ -1,194 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state.factory - -import androidx.paging.PagingData -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent -import com.tangem.core.ui.event.consumedEvent -import com.tangem.core.ui.event.triggeredEvent -import com.tangem.domain.tokens.CurrencyCompatibilityError -import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.domain.wallets.models.UserWallet -import com.tangem.managetokens.presentation.common.state.* -import com.tangem.managetokens.presentation.common.utils.CurrencyUtils -import com.tangem.managetokens.presentation.managetokens.state.* -import com.tangem.managetokens.presentation.managetokens.viewmodels.ManageTokensClickIntents -import com.tangem.managetokens.presentation.managetokens.viewmodels.ManageTokensUiEvents -import com.tangem.utils.Provider -import kotlinx.collections.immutable.toPersistentList -import kotlinx.coroutines.flow.Flow - -internal class ManageTokensStateFactory( - private val currentStateProvider: Provider, - private val clickIntents: ManageTokensClickIntents, - private val uiIntents: ManageTokensUiEvents, -) { - - fun getInitialState(tokens: Flow>): ManageTokensState { - return ManageTokensState( - searchBarState = SearchBarState( - query = "", - onQueryChange = clickIntents::onSearchQueryChange, - active = false, - onActiveChange = clickIntents::onSearchActiveChange, - ), - tokens = tokens, - addCustomTokenButton = AddCustomTokenButton( - isVisible = false, - onClick = clickIntents::onAddCustomTokensButtonClick, - ), - derivationNotification = null, - isLoading = false, - event = consumedEvent(), - chooseWalletState = ChooseWalletState.NoSelection, - onEmptySearchResult = uiIntents::onEmptySearchResult, - customTokenBottomSheetConfig = TangemBottomSheetConfig( - isShow = false, - onDismissRequest = uiIntents::onAddCustomTokenSheetDismissed, - content = TangemBottomSheetConfigContent.Empty, - ), - ) - } - - fun updateChooseWalletState( - wallets: List, - userWallets: List, - selectedWallet: UserWallet?, - ): ManageTokensState { - val chooseWalletState = when { - wallets.size == 1 -> { - ChooseWalletState.NoSelection - } - wallets.isEmpty() && userWallets.all { !it.isMultiCurrency } -> { - ChooseWalletState.Warning(ChooseWalletWarning.SINGLE_CURRENCY) - } - else -> { - var selectedWalletState: WalletState? = null - ChooseWalletState.Choose( - wallets = wallets.map { wallet -> - val walletState = WalletState( - walletId = wallet.walletId.stringValue, - artworkUrl = wallet.artworkUrl, - onSelected = clickIntents::onWalletSelected, - walletName = wallet.name, - ) - if (wallet.walletId.stringValue == selectedWallet?.walletId?.stringValue) { - selectedWalletState = walletState - } - walletState - }.toPersistentList(), - selectedWallet = selectedWalletState, - onChooseWalletClick = clickIntents::onChooseWalletClick, - onCloseChoosingWalletClick = clickIntents::onCloseChoosingWalletClick, - ) - } - } - return currentStateProvider().copy(chooseWalletState = chooseWalletState) - } - - fun showAddCustomTokensButton(show: Boolean): ManageTokensState { - return currentStateProvider().copy( - addCustomTokenButton = currentStateProvider().addCustomTokenButton.copy(isVisible = show), - ) - } - - fun updateSelectedWallet(selectedWalletId: String?): ManageTokensState { - val chooseWalletState = currentStateProvider().chooseWalletState - return currentStateProvider().copy( - showChooseWalletScreen = false, - chooseWalletState = if (chooseWalletState is ChooseWalletState.Choose) { - chooseWalletState.copy( - selectedWallet = chooseWalletState.wallets.find { - it.walletId == selectedWalletId - } ?: chooseWalletState.wallets.first(), - ) - } else { - chooseWalletState - }, - ) - } - - fun getStateAndTriggerEvent( - state: ManageTokensState, - event: Event, - setUiState: (ManageTokensState) -> Unit, - ): ManageTokensState { - return state.copy( - event = triggeredEvent( - data = event, - onConsume = { - val currentState = currentStateProvider() - setUiState(currentState.copy(event = consumedEvent())) - }, - ), - ) - } - - fun transformAddTokenErrorToAlert(error: CurrencyCompatibilityError, networkName: String): AlertState { - return when (error) { - CurrencyCompatibilityError.SolanaTokensUnsupported -> AlertState.TokensUnsupported(networkName) - CurrencyCompatibilityError.UnsupportedBlockchain -> AlertState.TokensUnsupportedBlockchainByCard( - networkName, - ) - CurrencyCompatibilityError.UnsupportedCurve -> AlertState.TokensUnsupportedCurve - } - } - - fun toggleNetworkState( - token: TokenItemState.Loaded, - network: NetworkItemState.Toggleable, - allAddedCurrencies: Collection, - ) { - network.changeToggleState() - val anyNetworkAdded = isAnyNetworkAdded( - networks = token.chooseNetworkState.nativeNetworks + token.chooseNetworkState.nonNativeNetworks, - allAddedCurrencies = allAddedCurrencies, - ) - val buttonType = if (anyNetworkAdded) TokenButtonType.EDIT else TokenButtonType.ADD - token.availableAction.value = buttonType - } - - private fun isAnyNetworkAdded( - networks: List, - allAddedCurrencies: Collection, - ): Boolean { - return networks.any { - it is NetworkItemState.Toggleable && CurrencyUtils.isAdded( - address = it.address, - networkId = it.id, - currencies = allAddedCurrencies, - ) - } - } - - fun updateTokenNetworksOnTokenSelection( - token: TokenItemState.Loaded, - addedCurrenciesOnWallet: Collection, - ) { - token.chooseNetworkState.nativeNetworks.forEach { - if (it is NetworkItemState.Toggleable) { - val isAdded = CurrencyUtils.isAdded(it.address, it.id, addedCurrenciesOnWallet) - if (isAdded != it.isAdded.value) (it as? NetworkItemState.Toggleable)?.changeToggleState() - } - } - token.chooseNetworkState.nonNativeNetworks.forEach { - if (it is NetworkItemState.Toggleable) { - val isAdded = CurrencyUtils.isAdded(it.address, it.id, addedCurrenciesOnWallet) - if (isAdded != it.isAdded.value) (it as? NetworkItemState.Toggleable)?.changeToggleState() - } - } - } - - fun updateDerivationNotification(totalNeeded: Int, totalWallets: Int, walletsToDerive: Int): ManageTokensState { - val derivationNotificationState = if (totalNeeded == 0) { - null - } else { - DerivationNotificationState( - totalNeeded = totalNeeded, - totalWallets = totalWallets, - walletsToDerive = walletsToDerive, - onGenerateClick = clickIntents::onGetAddressesClick, - ) - } - return currentStateProvider().copy(derivationNotification = derivationNotificationState) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/NetworkToNetworkItemStateConverter.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/NetworkToNetworkItemStateConverter.kt deleted file mode 100644 index 01af86d1f2..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/NetworkToNetworkItemStateConverter.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state.factory - -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf -import com.tangem.core.ui.extensions.getActiveIconResByNetworkId -import com.tangem.core.ui.extensions.getGreyedOutIconResByNetworkId -import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.domain.tokens.model.Token -import com.tangem.domain.wallets.models.UserWallet -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import com.tangem.managetokens.presentation.common.utils.CurrencyUtils -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState -import com.tangem.utils.Provider -import com.tangem.utils.converter.Converter - -internal class NetworkToNetworkItemStateConverter( - private val addedCurrenciesByWalletProvider: Provider>>, - private val selectedWalletProvider: Provider, - private val onNetworkToggleClick: (token: TokenItemState.Loaded, network: NetworkItemState.Toggleable) -> Unit, -) : Converter { - - override fun convert(value: Token.Network): NetworkItemState { - return createManageNetworkContent(value) - } - - private fun createManageNetworkContent(network: Token.Network): NetworkItemState { - val addedCurrencies = addedCurrenciesByWalletProvider()[selectedWalletProvider()] ?: emptyList() - val isAdded = CurrencyUtils.isAdded( - address = network.address, - networkId = network.networkId, - currencies = addedCurrencies, - ) - return NetworkItemState.Toggleable( - name = network.name, - iconResId = mutableIntStateOf( - getNetworkIconResId(isAdded, network.networkId), // todo - ), - isMainNetwork = isMainNetwork(network), - isAdded = mutableStateOf(isAdded), - id = network.networkId, - protocolName = network.standardType, - address = network.address, - decimals = network.decimalCount, - onToggleClick = onNetworkToggleClick, - ) - } - - private fun getNetworkIconResId(isAdded: Boolean, networkId: String): Int { - return if (isAdded) { - getActiveIconResByNetworkId(networkId) - } else { - getGreyedOutIconResByNetworkId(networkId) - } - } - - private fun isMainNetwork(network: Token.Network) = network.address == null -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/NetworksToChooseNetworkStateConverter.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/NetworksToChooseNetworkStateConverter.kt deleted file mode 100644 index 99509e85ea..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/NetworksToChooseNetworkStateConverter.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state.factory - -import com.tangem.domain.tokens.model.Token -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import com.tangem.managetokens.presentation.managetokens.state.ChooseNetworkState -import com.tangem.utils.converter.Converter -import kotlinx.collections.immutable.toPersistentList - -internal class NetworksToChooseNetworkStateConverter( - private val networkToNetworkItemStateConverter: NetworkToNetworkItemStateConverter, - private val onNonNativeNetworkHintClick: () -> Unit, - private val onCloseChooseNetworkScreen: () -> Unit, -) : Converter, ChooseNetworkState> { - - override fun convert(value: List): ChooseNetworkState { - return createChooseNetworksState(value) - } - - private fun createChooseNetworksState(networks: List): ChooseNetworkState { - val nativeNetworks = mutableListOf() - val nonNativeNetworks = mutableListOf() - networks.map { networkToNetworkItemStateConverter.convert(it) }.forEach { - if (it is NetworkItemState.Toggleable && it.isMainNetwork) { - nativeNetworks.add(it) - } else { - nonNativeNetworks.add(it) - } - } - return ChooseNetworkState( - nativeNetworks = nativeNetworks.toPersistentList(), - nonNativeNetworks = nonNativeNetworks.toPersistentList(), - onNonNativeNetworkHintClick = onNonNativeNetworkHintClick, - onCloseChooseNetworkScreen = onCloseChooseNetworkScreen, - ) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/QuotesToQuotesStateConverter.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/QuotesToQuotesStateConverter.kt deleted file mode 100644 index 972c004779..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/QuotesToQuotesStateConverter.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state.factory - -import com.tangem.core.ui.components.marketprice.PriceChangeType -import com.tangem.core.ui.components.marketprice.utils.PriceChangeConverter -import com.tangem.core.ui.utils.BigDecimalFormatter -import com.tangem.domain.tokens.model.Quote -import com.tangem.managetokens.presentation.managetokens.state.QuotesState -import com.tangem.utils.converter.Converter -import kotlinx.collections.immutable.persistentListOf -import java.math.BigDecimal - -@Suppress("MagicNumber") // TODO: remove when chart data is added (in [REDACTED_TASK_KEY] when endpoint is ready) -internal class QuotesToQuotesStateConverter : Converter { - override fun convert(value: Quote): QuotesState { - val priceChange = value.priceChange - return QuotesState.Content( - priceChange = BigDecimalFormatter.formatPercent( - percent = priceChange.movePointLeft(2), - useAbsoluteValue = true, - ), - changeType = priceChange.getPriceChangeType(), - chartData = // TODO (in [REDACTED_TASK_KEY] when endpoint is ready) - when (priceChange.getPriceChangeType()) { - PriceChangeType.UP -> persistentListOf(0f, 5f, 10f, 30f) - PriceChangeType.DOWN -> persistentListOf(15f, 12f, 13f, 18f, 10f, 3f) - PriceChangeType.NEUTRAL -> persistentListOf(0f, 0f, 0f, 0f) - }, - ) - } - - private fun BigDecimal.getPriceChangeType(): PriceChangeType { - return PriceChangeConverter.fromBigDecimal(value = this) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/TokenConverter.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/TokenConverter.kt deleted file mode 100644 index 156c65d70d..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/TokenConverter.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state.factory - -import androidx.compose.runtime.mutableStateOf -import com.tangem.core.ui.extensions.ImageReference -import com.tangem.core.ui.extensions.getTintForTokenIcon -import com.tangem.core.ui.extensions.tryGetBackgroundForTokenIcon -import com.tangem.core.ui.utils.BigDecimalFormatter -import com.tangem.domain.appcurrency.model.AppCurrency -import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.domain.tokens.model.Token -import com.tangem.managetokens.presentation.common.utils.CurrencyUtils -import com.tangem.managetokens.presentation.managetokens.state.QuotesState -import com.tangem.managetokens.presentation.managetokens.state.TokenButtonType -import com.tangem.managetokens.presentation.managetokens.state.TokenIconState -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState -import com.tangem.utils.Provider -import com.tangem.utils.converter.Converter - -internal class TokenConverter( - private val quotesStateConverter: QuotesToQuotesStateConverter, - private val networksToChooseNetworkStateConverter: NetworksToChooseNetworkStateConverter, - private val allAddedCurrencies: Provider>, - private val selectedAppCurrency: Provider, - private val onTokenItemButtonClick: (TokenItemState.Loaded) -> Unit, -) : Converter { - - override fun convert(value: Token): TokenItemState.Loaded { - val isAnyAdded = value.networks.any { network -> - CurrencyUtils.isAdded( - address = network.address, - networkId = network.networkId, - currencies = allAddedCurrencies(), - ) - } - val buttonType = when { - value.isAvailable && isAnyAdded -> TokenButtonType.EDIT - value.isAvailable && !isAnyAdded -> TokenButtonType.ADD - else -> TokenButtonType.NOT_AVAILABLE - } - - val background = tryGetBackgroundForTokenIcon(value.networks.firstOrNull()?.address ?: "") - val tint = getTintForTokenIcon(background) - - return TokenItemState.Loaded( - id = value.id, - name = value.name, - currencySymbol = value.symbol, - tokenId = value.id, - tokenIcon = TokenIconState( - ImageReference.Url(value.iconUrl), - placeholderBackground = background, - placeholderTint = tint, - ), - quotes = value.quote?.let { quotesStateConverter.convert(it) } ?: QuotesState.Unknown, - rate = value.quote?.fiatRate?.let { rate -> - BigDecimalFormatter.formatFiatAmount( - fiatAmount = rate, - fiatCurrencyCode = selectedAppCurrency().code, - fiatCurrencySymbol = selectedAppCurrency().symbol, - ) - }, - availableAction = mutableStateOf(buttonType), - chooseNetworkState = networksToChooseNetworkStateConverter.convert(value.networks), - onButtonClick = onTokenItemButtonClick, - ) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/TokenToCryptoCurrencyConverter.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/TokenToCryptoCurrencyConverter.kt deleted file mode 100644 index a7a6832cc6..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/factory/TokenToCryptoCurrencyConverter.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state.factory - -import com.tangem.data.tokens.utils.CryptoCurrencyFactory -import com.tangem.domain.common.DerivationStyleProvider -import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState -import com.tangem.utils.converter.Converter - -internal class TokenToCryptoCurrencyConverter( - private val network: NetworkItemState, - private val derivationStyleProvider: DerivationStyleProvider, -) : Converter { - - override fun convert(value: TokenItemState.Loaded): CryptoCurrency? { - return if (network is NetworkItemState.Toggleable && network.address != null) { - CryptoCurrencyFactory().createToken( - CryptoCurrencyFactory.Token( - symbol = value.currencySymbol, - name = value.name, - id = value.tokenId, - contractAddress = network.address, - decimals = requireNotNull(network.decimals), - ), - networkId = network.id, - derivationStyleProvider = derivationStyleProvider, - extraDerivationPath = null, - ) - } else { - CryptoCurrencyFactory().createCoin( - networkId = network.id, - derivationStyleProvider = derivationStyleProvider, - extraDerivationPath = null, - ) - } - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/ChooseNetworkStatePreviewData.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/ChooseNetworkStatePreviewData.kt deleted file mode 100644 index f66b65bc1b..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/ChooseNetworkStatePreviewData.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state.previewdata - -import androidx.compose.runtime.mutableStateOf -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import com.tangem.managetokens.presentation.managetokens.state.ChooseNetworkState -import kotlinx.collections.immutable.toImmutableList - -internal object ChooseNetworkStatePreviewData { - - val state = ChooseNetworkState( - nativeNetworks = nativeNetworks.toImmutableList(), - nonNativeNetworks = nonNativeNetworks.toImmutableList(), - onNonNativeNetworkHintClick = {}, - onCloseChooseNetworkScreen = {}, - ) -} - -internal val nativeNetworks = listOf( - NetworkItemState.Toggleable( - name = "Ethereum", - protocolName = "ETH", - iconResId = mutableStateOf(R.drawable.img_polygon_22), - isMainNetwork = true, - isAdded = mutableStateOf(true), - id = "", - onToggleClick = { _, _ -> }, - address = "", - decimals = 0, - ), -) - -internal val nonNativeNetworks = listOf( - NetworkItemState.Toggleable( - name = "Ethereum", - protocolName = "ETH", - iconResId = mutableStateOf(R.drawable.img_kusama_22), - isMainNetwork = false, - isAdded = mutableStateOf(true), - id = "1", - onToggleClick = { _, _ -> }, - address = "", - decimals = 0, - ), - NetworkItemState.Toggleable( - name = "BNB SMART CHAIN", - protocolName = "BEP20", - iconResId = mutableStateOf(R.drawable.ic_bsc_16), - isMainNetwork = false, - isAdded = mutableStateOf(false), - id = "2", - onToggleClick = { _, _ -> }, - address = "", - decimals = 0, - ), -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/DerivationNotificationStatePreviewData.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/DerivationNotificationStatePreviewData.kt deleted file mode 100644 index b5d88b814a..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/DerivationNotificationStatePreviewData.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state.previewdata - -import com.tangem.managetokens.presentation.managetokens.state.DerivationNotificationState - -object DerivationNotificationStatePreviewData { - val state = DerivationNotificationState( - totalNeeded = 5, - totalWallets = 3, - walletsToDerive = 2, - onGenerateClick = {}, - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/ManageTokensStatePreviewData.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/ManageTokensStatePreviewData.kt deleted file mode 100644 index eab841b41f..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/ManageTokensStatePreviewData.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state.previewdata - -import androidx.paging.PagingData -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent -import com.tangem.core.ui.event.consumedEvent -import com.tangem.managetokens.presentation.common.state.previewdata.ChooseWalletStatePreviewData -import com.tangem.managetokens.presentation.managetokens.state.* -import com.tangem.managetokens.presentation.managetokens.state.ManageTokensState -import com.tangem.managetokens.presentation.managetokens.state.SearchBarState -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState -import kotlinx.coroutines.flow.flowOf - -internal object ManageTokensStatePreviewData { - val loadedState: ManageTokensState - get() = ManageTokensState( - searchBarState = searchState, - tokens = flowOf(PagingData.from(tokens)), - isLoading = false, - addCustomTokenButton = AddCustomTokenButton(true, {}), - derivationNotification = DerivationNotificationStatePreviewData.state, - event = consumedEvent(), - chooseWalletState = ChooseWalletStatePreviewData.state, - onEmptySearchResult = {}, - customTokenBottomSheetConfig = TangemBottomSheetConfig(false, {}, TangemBottomSheetConfigContent.Empty), - ) - - val loadingState: ManageTokensState - get() = loadedState.copy(isLoading = true) - - private val tokens: List - get() = listOf( - TokenItemStatePreviewData.loadedPriceDown, - TokenItemStatePreviewData.loadedPriceUp, - TokenItemStatePreviewData.loadedPriceNeutral, - ) - - private val searchState: SearchBarState - get() = SearchBarState( - query = "", - onQueryChange = {}, - active = false, - onActiveChange = {}, - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/TokenItemStatePreviewData.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/TokenItemStatePreviewData.kt deleted file mode 100644 index 1ba8f760e6..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/TokenItemStatePreviewData.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.state.previewdata - -import androidx.compose.runtime.mutableStateOf -import androidx.compose.ui.graphics.Color -import com.tangem.core.ui.components.marketprice.PriceChangeType -import com.tangem.managetokens.presentation.managetokens.state.QuotesState -import com.tangem.managetokens.presentation.managetokens.state.TokenButtonType -import com.tangem.managetokens.presentation.managetokens.state.TokenIconState -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState -import kotlinx.collections.immutable.persistentListOf - -internal object TokenItemStatePreviewData { - - val tokenLoading: TokenItemState - get() = TokenItemState.Loading("id") - - val loadedPriceDown: TokenItemState - get() = TokenItemState.Loaded( - id = "BTC", - name = "Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin", - tokenId = "BTC", - currencySymbol = "BTC", - tokenIcon = tokenIconState, - quotes = QuotesState.Content( - priceChange = "0.43%", - changeType = PriceChangeType.DOWN, - chartData = persistentListOf(10f, 2f, 5f, 3f, 4f, 8f, 9f, 7f, 4f), - ), - rate = "31 285.72$", - availableAction = mutableStateOf(TokenButtonType.ADD), - onButtonClick = {}, - chooseNetworkState = ChooseNetworkStatePreviewData.state, - ) - - val loadedPriceUp: TokenItemState - get() = TokenItemState.Loaded( - id = "BTC", - name = "Bitcoin", - tokenId = "BTC", - currencySymbol = "BTC", - tokenIcon = tokenIconState, - quotes = QuotesState.Content( - priceChange = "0.43%", - changeType = PriceChangeType.UP, - chartData = persistentListOf(1f, 3f, 4f, 8f, 12f, 10f, 8f, 3f, 5f, 7f), - ), - rate = "31 285.72$", - availableAction = mutableStateOf(TokenButtonType.NOT_AVAILABLE), - onButtonClick = {}, - chooseNetworkState = ChooseNetworkStatePreviewData.state, - ) - - val loadedPriceNeutral: TokenItemState - get() = TokenItemState.Loaded( - id = "BTC", - name = "Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin", - tokenId = "BTC", - currencySymbol = "BTC", - tokenIcon = tokenIconState, - quotes = QuotesState.Content( - priceChange = "0.00%", - changeType = PriceChangeType.NEUTRAL, - chartData = persistentListOf(10f, 2f, 5f, 3f, 4f, 8f, 9f, 7f, 10f), - ), - rate = "31 285.72$", - availableAction = mutableStateOf(TokenButtonType.ADD), - onButtonClick = {}, - chooseNetworkState = ChooseNetworkStatePreviewData.state, - ) - - private val tokenIconState: TokenIconState - get() = TokenIconState( - iconReference = null, - placeholderTint = Color.White, - placeholderBackground = Color.Black, - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ChooseNetworkBottomSheet.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ChooseNetworkBottomSheet.kt deleted file mode 100644 index 5cbdc20a93..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ChooseNetworkBottomSheet.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui - -import androidx.compose.runtime.Composable -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent -import com.tangem.core.ui.res.TangemTheme -import com.tangem.managetokens.presentation.common.state.ChooseWalletState -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState - -@Composable -internal fun ChooseNetworkBottomSheet(config: TangemBottomSheetConfig) { - TangemBottomSheet( - config = config, - containerColor = TangemTheme.colors.background.tertiary, - ) { - ChooseNetworkScreen(state = it.selectedToken, walletState = it.chooseWalletState) - } -} - -internal class ChooseNetworkBottomSheetConfig( - val selectedToken: TokenItemState.Loaded, - val chooseWalletState: ChooseWalletState, -) : TangemBottomSheetConfigContent \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ChooseNetworkScreen.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ChooseNetworkScreen.kt deleted file mode 100644 index 2f5d51df8a..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ChooseNetworkScreen.kt +++ /dev/null @@ -1,201 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyListScope -import androidx.compose.material.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -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.SpacerH -import com.tangem.core.ui.components.SpacerW -import com.tangem.core.ui.components.WarningCardTitleOnly -import com.tangem.core.ui.decorations.roundedShapeItemDecoration -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.core.ui.res.TangemTheme -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.common.state.ChooseWalletState -import com.tangem.managetokens.presentation.common.state.previewdata.ChooseWalletStatePreviewData -import com.tangem.managetokens.presentation.common.ui.components.NetworkItem -import com.tangem.managetokens.presentation.common.ui.components.SimpleSelectionBlock -import com.tangem.managetokens.presentation.managetokens.state.ChooseNetworkState -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState -import com.tangem.managetokens.presentation.managetokens.state.previewdata.TokenItemStatePreviewData - -@Composable -internal fun ChooseNetworkScreen( - state: TokenItemState.Loaded, - walletState: ChooseWalletState, - modifier: Modifier = Modifier, -) { - val networkState = state.chooseNetworkState - LazyColumn( - contentPadding = PaddingValues( - start = TangemTheme.dimens.spacing16, - end = TangemTheme.dimens.spacing16, - bottom = TangemTheme.dimens.spacing16, - ), - modifier = modifier - .background(TangemTheme.colors.background.tertiary), - ) { - item { - Text( - text = stringResource(id = R.string.manage_tokens_network_selector_title), - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.subtitle1, - textAlign = TextAlign.Center, - modifier = Modifier - .fillMaxWidth(), - ) - } - - when (walletState) { - is ChooseWalletState.Choose -> { - item { - SpacerH(height = TangemTheme.dimens.spacing10) - } - item { - SimpleSelectionBlock( - title = stringResource(id = R.string.manage_tokens_network_selector_wallet), - subtitle = walletState.selectedWallet?.walletName ?: "", - onClick = walletState.onChooseWalletClick, - ) - } - } - ChooseWalletState.NoSelection -> Unit - is ChooseWalletState.Warning -> { - item { - SpacerH(height = TangemTheme.dimens.spacing10) - } - item { - WarningCardTitleOnly( - title = stringResource(id = R.string.manage_tokens_wallet_support_only_one_network_title), - ) - } - } - } - - item { - SpacerH(height = TangemTheme.dimens.spacing16) - } - - if (networkState.nativeNetworks.isNotEmpty()) { - this@LazyColumn.nativeNetworks(networkState = networkState, tokenState = state) - } - - if (networkState.nonNativeNetworks.isNotEmpty()) { - this@LazyColumn.nonNativeNetworks(networkState = networkState, tokenState = state) - } - } -} - -private fun LazyListScope.nativeNetworks(networkState: ChooseNetworkState, tokenState: TokenItemState.Loaded) { - item { - Text( - text = stringResource(id = R.string.manage_tokens_network_selector_native_title), - color = TangemTheme.colors.text.tertiary, - style = TangemTheme.typography.caption1, - ) - SpacerH(height = TangemTheme.dimens.spacing2) - Text( - text = stringResource(id = R.string.manage_tokens_network_selector_native_subtitle), - color = TangemTheme.colors.text.tertiary, - style = TangemTheme.typography.caption2, - ) - SpacerH(height = TangemTheme.dimens.spacing8) - } - - items( - count = networkState.nativeNetworks.count(), - key = { index -> networkState.nativeNetworks[index].id }, - ) { index -> - NetworkItem( - state = networkState.nativeNetworks[index], - tokenState = tokenState, - modifier = Modifier - .roundedShapeItemDecoration( - currentIndex = index, - lastIndex = networkState.nativeNetworks.lastIndex, - addDefaultPadding = false, - ), - ) - } - - item { - SpacerH(height = TangemTheme.dimens.spacing16) - } -} - -private fun LazyListScope.nonNativeNetworks(networkState: ChooseNetworkState, tokenState: TokenItemState.Loaded) { - item { - NonNativeNetworksHeader(networkState.onNonNativeNetworkHintClick) - SpacerH(height = TangemTheme.dimens.spacing8) - } - - items( - count = networkState.nonNativeNetworks.count(), - key = { index -> networkState.nonNativeNetworks[index].id }, - ) { index -> - NetworkItem( - state = networkState.nonNativeNetworks[index], - tokenState = tokenState, - modifier = Modifier - .roundedShapeItemDecoration( - currentIndex = index, - lastIndex = networkState.nonNativeNetworks.lastIndex, - addDefaultPadding = false, - ), - ) - } - - item { - SpacerH(height = TangemTheme.dimens.spacing16) - } -} - -@Composable -private fun NonNativeNetworksHeader(onNonNativeNetworkHintClick: () -> Unit) { - Column { - Row { - Text( - text = stringResource(id = R.string.manage_tokens_network_selector_non_native_title), - color = TangemTheme.colors.text.tertiary, - style = TangemTheme.typography.caption1, - ) - SpacerW(width = TangemTheme.dimens.spacing2) - Icon( - painter = painterResource(id = R.drawable.ic_information_24), - tint = TangemTheme.colors.icon.inactive, - contentDescription = null, - modifier = Modifier - .size(TangemTheme.dimens.size16) - .clickable { onNonNativeNetworkHintClick() }, - ) - } - SpacerH(height = TangemTheme.dimens.spacing2) - Text( - text = stringResource(id = R.string.manage_tokens_network_selector_non_native_subtitle), - color = TangemTheme.colors.text.tertiary, - style = TangemTheme.typography.caption2, - ) - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun Preview_ChooseNetworkScreen() { - TangemThemePreview { - ChooseNetworkScreen( - state = TokenItemStatePreviewData.loadedPriceDown as TokenItemState.Loaded, - walletState = ChooseWalletStatePreviewData.state, - ) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ManageTokensScreen.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ManageTokensScreen.kt deleted file mode 100644 index 6b91d83e18..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/ManageTokensScreen.kt +++ /dev/null @@ -1,197 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui - -import android.content.res.Configuration -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material.Surface -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.onGloballyPositioned -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import androidx.paging.LoadState -import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.collectAsLazyPagingItems -import com.tangem.core.ui.components.Keyboard -import com.tangem.core.ui.components.SpacerH18 -import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig -import com.tangem.core.ui.components.keyboardAsState -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.core.ui.res.TangemTheme -import com.tangem.managetokens.presentation.addcustomtoken.ui.AddCustomTokenBottomSheet -import com.tangem.managetokens.presentation.common.state.AlertState -import com.tangem.managetokens.presentation.common.state.ChooseWalletState -import com.tangem.managetokens.presentation.common.ui.ChooseWalletBottomSheet -import com.tangem.managetokens.presentation.common.ui.ChooseWalletBottomSheetConfig -import com.tangem.managetokens.presentation.common.ui.EventEffect -import com.tangem.managetokens.presentation.common.ui.components.Alert -import com.tangem.managetokens.presentation.managetokens.state.ManageTokensState -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState -import com.tangem.managetokens.presentation.managetokens.state.previewdata.ManageTokensStatePreviewData -import com.tangem.managetokens.presentation.managetokens.ui.components.DerivationNotification -import com.tangem.managetokens.presentation.managetokens.ui.components.TokensList -import com.tangem.managetokens.presentation.managetokens.ui.components.TokensSearchBar - -@Composable -internal fun ManageTokensScreen(state: ManageTokensState, onHeaderSizeChange: (Dp) -> Unit) { - var alertState by remember { mutableStateOf(value = null) } - - EventEffect( - event = state.event, - onAlertStateSet = { alertState = it }, - ) - alertState?.let { - Alert(state = it, onDismiss = { alertState = null }) - } - - Content(state = state, onHeaderSizeChange = onHeaderSizeChange) - - AddCustomTokenBottomSheet(state.customTokenBottomSheetConfig) -} - -@Composable -private fun Content(state: ManageTokensState, onHeaderSizeChange: (Dp) -> Unit) { - val keyboard by keyboardAsState() - val density = LocalDensity.current - var tokenListAlertBottomPadding by remember(keyboard is Keyboard.Opened) { mutableStateOf(0.dp) } - - Box( - modifier = Modifier - .fillMaxSize() - .imePadding() - .background(color = TangemTheme.colors.background.primary), - ) { - Column { - val listState = rememberLazyListState() - val raiseSearchBar by remember { derivedStateOf { listState.firstVisibleItemIndex > 0 } } - val elevation by animateDpAsState( - targetValue = if (raiseSearchBar) TangemTheme.dimens.elevation8 else TangemTheme.dimens.elevation0, - label = "top_bar_elevation", - ) - - Surface( - elevation = elevation, - modifier = Modifier.onGloballyPositioned { - with(density) { onHeaderSizeChange(it.size.height.toDp()) } - }, - ) { - TokensSearchBar( - state = state.searchBarState, - modifier = Modifier - .background(color = TangemTheme.colors.background.primary) - .padding( - start = TangemTheme.dimens.spacing16, - end = TangemTheme.dimens.spacing16, - bottom = TangemTheme.dimens.spacing4, - ), - ) - } - - SpacerH18() - - val tokens = state.tokens.collectAsLazyPagingItems() - val query = state.searchBarState.query - - TrackPossibleEmptySearchResult( - tokens = tokens, - query = query, - onEmptySearchResult = state.onEmptySearchResult, - ) - - TokensList( - modifier = Modifier.padding(bottom = tokenListAlertBottomPadding), - tokens = tokens, - addCustomTokenButton = state.addCustomTokenButton, - ) - } - - state.selectedToken?.let { selectedToken -> - ManageTokensBottomSheet(selectedToken = selectedToken, state = state) - } - - state.derivationNotification?.let { - if (keyboard is Keyboard.Closed) { - DerivationNotification( - config = it.config, - modifier = Modifier - .align(Alignment.BottomCenter) - .onGloballyPositioned { - with(density) { tokenListAlertBottomPadding = it.size.height.toDp() } - }, - ) - DisposableEffect(Unit) { - onDispose { tokenListAlertBottomPadding = 0.dp } - } - } - } - } -} - -@Composable -private fun TrackPossibleEmptySearchResult( - tokens: LazyPagingItems, - query: String, - onEmptySearchResult: (String) -> Unit, -) { - val wasLoading = remember { mutableStateOf(false) } - - LaunchedEffect(tokens.loadState) { - val isLoading = tokens.loadState.refresh == LoadState.Loading - val stoppedLoading = wasLoading.value && !isLoading - val queryAndTokensCondition = query.isNotEmpty() && tokens.itemSnapshotList.isEmpty() - - if (stoppedLoading && queryAndTokensCondition) { - onEmptySearchResult(query) - } - - wasLoading.value = isLoading - } -} - -@Composable -private fun ManageTokensBottomSheet(selectedToken: TokenItemState.Loaded, state: ManageTokensState) { - if (state.showChooseWalletScreen && state.chooseWalletState is ChooseWalletState.Choose) { - val config = TangemBottomSheetConfig( - isShow = true, - content = ChooseWalletBottomSheetConfig(state.chooseWalletState), - onDismissRequest = state.chooseWalletState.onCloseChoosingWalletClick, - ) - ChooseWalletBottomSheet(config) - } else { - val config = TangemBottomSheetConfig( - isShow = true, - content = ChooseNetworkBottomSheetConfig( - selectedToken = selectedToken, - chooseWalletState = state.chooseWalletState, - ), - onDismissRequest = selectedToken.chooseNetworkState.onCloseChooseNetworkScreen, - ) - ChooseNetworkBottomSheet(config) - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun Preview_ManageTokensScreen( - @PreviewParameter(ManageTokensConfigProvider::class) - state: ManageTokensState, -) { - TangemThemePreview { - ManageTokensScreen(state) {} - } -} - -private class ManageTokensConfigProvider : CollectionPreviewParameterProvider( - collection = listOf( - ManageTokensStatePreviewData.loadingState, - ManageTokensStatePreviewData.loadedState, - ), -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/AddCustomTokenButton.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/AddCustomTokenButton.kt deleted file mode 100644 index 32962c70db..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/AddCustomTokenButton.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui.components - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -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.tooling.preview.Preview -import com.tangem.core.ui.components.SpacerW -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.features.managetokens.impl.R - -@Composable -internal fun AddCustomTokenButton(onButtonClick: () -> Unit, modifier: Modifier = Modifier) { - Row( - horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically, - modifier = modifier - .defaultMinSize(minHeight = TangemTheme.dimens.size68) - .fillMaxWidth() - .clickable { onButtonClick() } - .padding(horizontal = TangemTheme.dimens.spacing16), - ) { - Box( - modifier = Modifier - .size(TangemTheme.dimens.size36) - .background(color = TangemTheme.colors.button.secondary, shape = CircleShape), - contentAlignment = Alignment.Center, - ) { - Icon( - painter = painterResource(id = R.drawable.ic_plus_24), - contentDescription = null, - tint = TangemTheme.colors.icon.informative, - ) - } - SpacerW(width = TangemTheme.dimens.spacing12) - Text( - text = stringResource(id = R.string.add_custom_token_title), - style = TangemTheme.typography.subtitle2, - color = TangemTheme.colors.text.tertiary, - ) - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun AddCustomTokenButton_Preview() { - TangemThemePreview { - AddCustomTokenButton(onButtonClick = { }) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/DerivationNotification.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/DerivationNotification.kt deleted file mode 100644 index d1f3822c9b..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/DerivationNotification.kt +++ /dev/null @@ -1,138 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui.components - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Card -import androidx.compose.material.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.PrimaryButtonIconEndTwoLines -import com.tangem.core.ui.components.SpacerW -import com.tangem.core.ui.components.notifications.NotificationConfig -import com.tangem.core.ui.extensions.TextReference -import com.tangem.core.ui.extensions.resolveReference -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.core.ui.res.TangemTheme -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.managetokens.state.previewdata.DerivationNotificationStatePreviewData - -@Composable -internal fun DerivationNotification(config: NotificationConfig, modifier: Modifier = Modifier) { - BaseContainer( - modifier = modifier, - ) { - Column( - modifier = Modifier.padding(all = TangemTheme.dimens.spacing16), - verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing16), - ) { - MainContent( - iconResId = config.iconResId, - iconTint = TangemTheme.colors.icon.accent, - title = config.title, - subtitle = config.subtitle, - ) - val buttonConfig = config.buttonsState - if (buttonConfig is NotificationConfig.ButtonsState.PrimaryButtonConfig) { - PrimaryButtonIconEndTwoLines( - text = buttonConfig.text.resolveReference(), - iconResId = buttonConfig.iconResId ?: R.drawable.ic_tangem_24, - onClick = buttonConfig.onClick, - modifier = Modifier - .fillMaxWidth(), - additionalText = buttonConfig.additionalText?.resolveReference(), - ) - } - } - } -} - -@Composable -private fun BaseContainer(modifier: Modifier = Modifier, content: @Composable BoxScope.() -> Unit) { - Card( - modifier = modifier - .defaultMinSize(minHeight = TangemTheme.dimens.size62) - .fillMaxWidth(), - shape = RoundedCornerShape( - topStart = TangemTheme.dimens.radius16, - topEnd = TangemTheme.dimens.radius16, - ), - elevation = TangemTheme.dimens.elevation12, - backgroundColor = TangemTheme.colors.background.action, - ) { - Box(content = content) - } -} - -@Composable -private fun MainContent(iconResId: Int, iconTint: Color, title: TextReference, subtitle: TextReference) { - Row { - NotificationIcon(iconResId = iconResId, iconTint = iconTint) - SpacerW(width = TangemTheme.dimens.spacing10) - TextsBlock(title = title, subtitle = subtitle) - } -} - -@Composable -private fun RowScope.NotificationIcon(iconResId: Int, iconTint: Color) { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .align(alignment = Alignment.CenterVertically), - ) { - Box( - modifier = Modifier - .size(TangemTheme.dimens.size36) - .background( - color = iconTint.copy(alpha = 0.12f), - shape = CircleShape, - ), - ) - Box( - modifier = Modifier - .size(TangemTheme.dimens.size16) - .background( - color = TangemTheme.colors.background.action, - shape = CircleShape, - ), - ) - Icon( - painter = painterResource(id = iconResId), - contentDescription = null, - tint = iconTint, - ) - } -} - -@Composable -private fun TextsBlock(title: TextReference, subtitle: TextReference) { - Column(verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing2)) { - Text( - text = title.resolveReference(), - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.button, - ) - - Text( - text = subtitle.resolveReference(), - color = TangemTheme.colors.text.tertiary, - style = TangemTheme.typography.caption2, - ) - } -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun Preview_ManageTokensScreen() { - TangemThemePreview { - DerivationNotification(DerivationNotificationStatePreviewData.state.config) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/PriceChangesChart.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/PriceChangesChart.kt deleted file mode 100644 index 1a18c5ee93..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/PriceChangesChart.kt +++ /dev/null @@ -1,134 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui.components - -import androidx.compose.foundation.Canvas -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.geometry.Size -import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.Path -import androidx.compose.ui.graphics.drawscope.DrawScope -import androidx.compose.ui.graphics.drawscope.Stroke -import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.res.TangemThemePreview -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf - -/** - * A chart with a solid line and gradient underneath. It can accept values of any range and number. - * If the last value is bigger or equal to the first, the chart is of accent color, otherwise it's warning color. - * - * @param values a list of float values for a chart. - **/ -@Composable -fun PriceChangesChart(values: ImmutableList, modifier: Modifier = Modifier) { - Row(modifier = modifier) { - if (values.size < 2) return // escape without drawing when there are not enough points - - val lineColor = if (values.last() >= values.first()) { - TangemTheme.colors.icon.accent - } else { - TangemTheme.colors.icon.warning - } - val gradient = Brush.verticalGradient( - colors = listOf(lineColor.copy(alpha = 0.21f), lineColor.copy(alpha = 0.0f)), - ) - Chart(list = values, lineColor = lineColor, gradient = gradient, modifier = Modifier.weight(1f)) - } -} - -@Composable -private fun Chart(list: ImmutableList, lineColor: Color, gradient: Brush, modifier: Modifier = Modifier) { - val max = list.max() - val min = list.min() - val zipList: List> = list.zipWithNext() - - for (pair in zipList) { - val fromValuePercentage = getValuePercentageForRange(pair.first, max, min) - val toValuePercentage = getValuePercentageForRange(pair.second, max, min) - - Canvas( - modifier = modifier.fillMaxHeight(), - onDraw = { - val fromPoint = Offset(x = 0f, y = size.height.times(1 - fromValuePercentage)) - val toPoint = Offset(x = size.width, y = size.height.times(1 - toValuePercentage)) - - val path = drawChartLineAndCreatePath(fromPoint = fromPoint, toPoint = toPoint, lineColor = lineColor) - - fillChart( - path = path, - fromPoint = fromPoint, - toPoint = toPoint, - size = size, - gradient = gradient, - ) - }, - ) - } -} - -private fun DrawScope.drawChartLineAndCreatePath(fromPoint: Offset, toPoint: Offset, lineColor: Color): Path { - val path = Path() - path.moveTo(fromPoint.x, fromPoint.y) - path.lineTo(toPoint.x, toPoint.y) - drawPath( - path = path, - color = lineColor, - style = Stroke(width = 1f), - ) - return path -} - -private fun DrawScope.fillChart(path: Path, fromPoint: Offset, toPoint: Offset, size: Size, gradient: Brush) { - path.lineTo(toPoint.x, size.height) - path.lineTo(fromPoint.x, size.height) - path.lineTo(0f, fromPoint.y) - drawPath( - path = path, - brush = gradient, - ) -} - -private fun getValuePercentageForRange(value: Float, max: Float, min: Float): Float { - return if (max == min) { // to draw a straight line when all values are the same - val modifiedMax = max + 1 - val modifiedMin = min - 1 - (value - modifiedMin) / (modifiedMax - modifiedMin) - } else { - (value - min) / (max - min) - } -} - -@Preview(widthDp = 150, heightDp = 150, showBackground = true) -@Composable -private fun Chart_Positive_Preview() { - TangemThemePreview(isDark = true) { - PriceChangesChart( - persistentListOf(1f, 2f, 4f, 1f, 5f), - ) - } -} - -@Preview(widthDp = 150, heightDp = 150, showBackground = true) -@Composable -private fun Chart_Negative_Preview() { - TangemThemePreview(isDark = true) { - PriceChangesChart( - persistentListOf(10f, 2f, 4f, 1f, 5f), - ) - } -} - -@Preview(widthDp = 150, heightDp = 150, showBackground = true) -@Composable -private fun Chart_Neutral_Preview() { - TangemThemePreview(isDark = true) { - PriceChangesChart( - persistentListOf(5f, 2f, 4f, 1f, 5f), - ) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/SearchBar.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/SearchBar.kt deleted file mode 100644 index 8faf911ebb..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/SearchBar.kt +++ /dev/null @@ -1,138 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui.components - -import android.content.res.Configuration -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.* -import androidx.compose.runtime.* -import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.onFocusChanged -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.core.ui.res.TangemTheme -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.managetokens.state.SearchBarState - -@OptIn(ExperimentalComposeUiApi::class) -@Composable -internal fun TokensSearchBar(state: SearchBarState, modifier: Modifier = Modifier) { - val keyboardController = LocalSoftwareKeyboardController.current - val focusManager = LocalFocusManager.current - - TextField( - value = state.query, - onValueChange = state.onQueryChange, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Search), - keyboardActions = KeyboardActions( - onSearch = { - keyboardController?.hide() - focusManager.clearFocus() - }, - ), - singleLine = true, - maxLines = 1, - textStyle = TangemTheme.typography.body2.copy( - color = TangemTheme.colors.text.primary1, - ), - leadingIcon = { - Icon( - painter = painterResource(id = R.drawable.ic_search_24), - tint = TangemTheme.colors.icon.informative, - contentDescription = null, - modifier = Modifier.clickable { state.onActiveChange(true) }, - ) - }, - trailingIcon = { - if (state.query.isNotEmpty() || state.active) { - IconButton( - onClick = { - if (state.query.isNotEmpty()) { - state.onQueryChange("") - } - focusManager.clearFocus() - keyboardController?.hide() - state.onActiveChange(false) - }, - ) { - Icon( - painter = painterResource(id = R.drawable.ic_close), - tint = TangemTheme.colors.icon.informative, - contentDescription = null, - ) - } - } - }, - placeholder = { - Text( - text = stringResource(R.string.manage_tokens_search_placeholder), - color = TangemTheme.colors.text.tertiary, - style = TangemTheme.typography.body2, - ) - }, - shape = RoundedCornerShape(TangemTheme.dimens.radius36), - colors = searchbarTextFieldColors(), - modifier = modifier - .fillMaxWidth() - .onFocusChanged { - if (it.isFocused) { - state.onActiveChange(true) - } else { - state.onActiveChange(false) - } - }, - ) -} - -@Composable -private fun searchbarTextFieldColors(): TextFieldColors { - return TextFieldDefaults.textFieldColors( - backgroundColor = TangemTheme.colors.field.primary, - textColor = TangemTheme.colors.text.primary1, - cursorColor = TangemTheme.colors.icon.primary1, - focusedIndicatorColor = Color.Transparent, - unfocusedIndicatorColor = Color.Transparent, - disabledIndicatorColor = Color.Transparent, - ) -} - -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun Preview_TokensSearchBar( - @PreviewParameter(SearchBarkConfigProvider::class) - state: SearchBarState, -) { - TangemThemePreview { - TokensSearchBar(state) - } -} - -private class SearchBarkConfigProvider : CollectionPreviewParameterProvider( - collection = listOf( - SearchBarState( - query = "BTC", - onQueryChange = {}, - active = true, - onActiveChange = {}, - ), - SearchBarState( - query = "", - onQueryChange = {}, - active = false, - onActiveChange = {}, - ), - ), -) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenButton.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenButton.kt deleted file mode 100644 index 3829ec91db..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenButton.kt +++ /dev/null @@ -1,85 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui.components - -import android.content.res.Configuration -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.size -import androidx.compose.material.Icon -import androidx.compose.material.ripple.rememberRipple -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.tangem.core.ui.components.buttons.PrimarySmallButton -import com.tangem.core.ui.components.buttons.SecondarySmallButton -import com.tangem.core.ui.components.buttons.SmallButtonConfig -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.core.ui.res.TangemTheme -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.managetokens.state.TokenButtonType - -@Composable -internal fun TokenButton(type: TokenButtonType, onClick: () -> Unit, modifier: Modifier = Modifier) { - when (type) { - TokenButtonType.ADD -> PrimarySmallButton( - config = SmallButtonConfig( - text = resourceReference(R.string.manage_tokens_add), - onClick = onClick, - ), - modifier = modifier, - ) - TokenButtonType.EDIT -> SecondarySmallButton( - config = SmallButtonConfig( - text = resourceReference(R.string.manage_tokens_edit), - onClick = onClick, - ), - modifier = modifier, - ) - TokenButtonType.NOT_AVAILABLE -> { - Box( - modifier = modifier - .size(height = TangemTheme.dimens.size24, width = TangemTheme.dimens.size46) - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = rememberRipple( - bounded = false, - radius = TangemTheme.dimens.size20, - ), - onClick = onClick, - ), - contentAlignment = Alignment.Center, - ) { - Icon( - modifier = Modifier - .size(TangemTheme.dimens.size20), - painter = painterResource(id = R.drawable.ic_information_24), - tint = TangemTheme.colors.icon.informative, - contentDescription = null, - ) - } - } - } -} - -@Preview(backgroundColor = 0xffffff, showBackground = true) -@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun TokenButton_Preview(@PreviewParameter(TokenButtonTypeProvider::class) type: TokenButtonType) { - TangemThemePreview { - TokenButton(type = type, {}) - } -} - -private class TokenButtonTypeProvider : PreviewParameterProvider { - override val values = sequenceOf( - TokenButtonType.ADD, - TokenButtonType.EDIT, - TokenButtonType.NOT_AVAILABLE, - ) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenIcon.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenIcon.kt deleted file mode 100644 index 262ebcf808..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenIcon.kt +++ /dev/null @@ -1,121 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui.components - -import androidx.compose.foundation.background -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.Icon -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.toArgb -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.painterResource -import coil.compose.SubcomposeAsyncImage -import coil.request.ImageRequest -import com.tangem.core.ui.components.CircleShimmer -import com.tangem.core.ui.extensions.ImageReference -import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.utils.ImageBackgroundContrastChecker -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.managetokens.state.TokenIconState -import kotlinx.coroutines.launch - -@Composable -internal fun TokenIcon(state: TokenIconState, modifier: Modifier = Modifier) { - val iconModifier = modifier.size(TangemTheme.dimens.size36) - if (state.iconReference != null) { - DefaultCurrencyIcon( - modifier = iconModifier, - iconReference = state.iconReference, - errorIcon = { - PlaceholderIcon( - modifier = iconModifier, - tint = state.placeholderTint, - background = state.placeholderBackground, - ) - }, - ) - } else { - PlaceholderIcon( - modifier = iconModifier, - tint = state.placeholderTint, - background = state.placeholderBackground, - ) - } -} - -@Composable -private fun PlaceholderIcon(tint: Color, background: Color, modifier: Modifier = Modifier) { - Box( - modifier = modifier - .background( - color = background, - shape = CircleShape, - ), - contentAlignment = Alignment.Center, - ) { - Icon( - modifier = Modifier.matchParentSize(), - painter = painterResource(id = R.drawable.ic_custom_token_44), - tint = tint, - contentDescription = null, - ) - } -} - -@Composable -private inline fun DefaultCurrencyIcon( - iconReference: ImageReference, - crossinline errorIcon: @Composable () -> Unit, - modifier: Modifier = Modifier, -) { - var iconBackgroundColor by remember { mutableStateOf(Color.Transparent) } - var isBackgroundColorDefined by remember { mutableStateOf(false) } - val itemBackgroundColor = TangemTheme.colors.background.primary.toArgb() - val isDarkTheme = isSystemInDarkTheme() - val coroutineScope = rememberCoroutineScope() - - val pixelsSize = with(LocalDensity.current) { TangemTheme.dimens.size36.roundToPx() } - - SubcomposeAsyncImage( - modifier = modifier - .background( - color = iconBackgroundColor, - shape = TangemTheme.shapes.roundedCorners8, - ), - model = ImageRequest.Builder(context = LocalContext.current) - .data(iconReference.getReference()) - .size(size = pixelsSize) - .memoryCacheKey(key = iconReference.getReference().toString() + pixelsSize) - .crossfade(enable = true) - .allowHardware(false) - .listener( - onSuccess = { _, result -> - if (!isBackgroundColorDefined && isDarkTheme) { - coroutineScope.launch { - val color = ImageBackgroundContrastChecker( - drawable = result.drawable, - backgroundColor = itemBackgroundColor, - size = pixelsSize, - ).getContrastColor(isDarkTheme = true) - iconBackgroundColor = color - isBackgroundColorDefined = true - } - } - }, - ) - .build(), - loading = { LoadingIcon() }, - error = { errorIcon() }, - contentDescription = null, - ) -} - -@Composable -internal fun LoadingIcon(modifier: Modifier = Modifier) { - CircleShimmer(modifier = modifier) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenPriceChange.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenPriceChange.kt deleted file mode 100644 index 28b7691794..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenPriceChange.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui.components - -import androidx.compose.animation.AnimatedContent -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.material3.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.style.TextOverflow -import com.tangem.core.ui.components.SpacerW4 -import com.tangem.core.ui.components.marketprice.PriceChangeType -import com.tangem.core.ui.res.TangemTheme -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.managetokens.state.QuotesState - -@Composable -internal fun TokenPriceChange(state: QuotesState, modifier: Modifier = Modifier) { - when (state) { - is QuotesState.Content -> - PriceChangeBlock(modifier = modifier, type = state.changeType, text = state.priceChange) - QuotesState.Unknown -> PriceChangeBlock(modifier = modifier) - } -} - -@Composable -private fun PriceChangeBlock(modifier: Modifier = Modifier, type: PriceChangeType? = null, text: String? = null) { - Row( - modifier = modifier, - horizontalArrangement = Arrangement.End, - verticalAlignment = Alignment.CenterVertically, - ) { - PriceChangeIcon(type = type) - SpacerW4() - PriceChangeText(type = type, text = text) - } -} - -@Composable -private fun PriceChangeIcon(type: PriceChangeType?) { - AnimatedContent(targetState = type, label = "Update the price change's arrow") { animatedType -> - animatedType ?: return@AnimatedContent - - Icon( - painter = painterResource( - id = when (animatedType) { - PriceChangeType.UP -> R.drawable.ic_arrow_up_8 - PriceChangeType.DOWN -> R.drawable.ic_arrow_down_8 - PriceChangeType.NEUTRAL -> R.drawable.ic_elipse_8 - }, - ), - tint = when (animatedType) { - PriceChangeType.UP -> TangemTheme.colors.icon.accent - PriceChangeType.DOWN -> TangemTheme.colors.icon.warning - PriceChangeType.NEUTRAL -> TangemTheme.colors.icon.inactive - }, - contentDescription = null, - ) - } -} - -@Composable -private fun PriceChangeText(type: PriceChangeType?, text: String?) { - AnimatedContent(targetState = text, label = "Update the price change's text") { animatedText -> - animatedText ?: return@AnimatedContent - - Text( - text = animatedText, - color = when (type) { - PriceChangeType.UP -> TangemTheme.colors.text.accent - PriceChangeType.DOWN -> TangemTheme.colors.text.warning - PriceChangeType.NEUTRAL -> TangemTheme.colors.text.disabled - null -> TangemTheme.colors.text.primary1 - }, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - style = TangemTheme.typography.body2, - ) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenRowItem.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenRowItem.kt deleted file mode 100644 index 50cf504643..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokenRowItem.kt +++ /dev/null @@ -1,203 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui.components - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.ReadOnlyComposable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider -import androidx.compose.ui.unit.Dp -import com.tangem.core.ui.components.* -import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.core.ui.res.TangemTheme -import com.tangem.managetokens.presentation.managetokens.state.QuotesState -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState -import com.tangem.managetokens.presentation.managetokens.state.previewdata.TokenItemStatePreviewData - -private val TOKEN_ITEM_HEIGHT: Dp - @Composable - @ReadOnlyComposable - get() = TangemTheme.dimens.size68 - -@Composable -internal fun TokenRowItem(state: TokenItemState, modifier: Modifier = Modifier) { - when (state) { - is TokenItemState.Loading -> LoadingTokenItem(modifier) - is TokenItemState.Loaded -> LoadedTokenItem(state, modifier) - } -} - -@Composable -private fun LoadedTokenItem(state: TokenItemState.Loaded, modifier: Modifier = Modifier) { - BoxWithConstraints( - modifier = modifier - .fillMaxWidth() - .defaultMinSize(minHeight = TOKEN_ITEM_HEIGHT) - .background(TangemTheme.colors.background.primary), - contentAlignment = Alignment.CenterStart, - ) { - val width = maxWidth - - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16), - ) { - TokenIcon(state = state.tokenIcon) - SpacerW12() - - Column( - modifier = Modifier - .weight(weight = 1f), - ) { - TokenName(name = state.name, currencyId = state.currencySymbol) - TokenPriceData(price = state.rate, quotesState = state.quotes) - } - SpacerW24() - - if (width > TangemTheme.dimens.size350 && // hide chart for small screens - state.quotes is QuotesState.Content - ) { - Chart(quotes = state.quotes) - SpacerW24() - } - - TokenButton( - type = state.availableAction.value, - onClick = { state.onButtonClick(state) }, - ) - } - } -} - -@Composable -private fun TokenName(name: String, currencyId: String) { - Row { - Text( - text = name, - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.subtitle2, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - modifier = Modifier - .weight(weight = 1f, fill = false), - ) - SpacerW(width = TangemTheme.dimens.spacing6) - Text( - text = currencyId, - color = TangemTheme.colors.text.tertiary, - style = TangemTheme.typography.body2, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - } -} - -@Composable -private fun TokenPriceData(price: String?, quotesState: QuotesState) { - if (price != null) { - Row { - Text( - text = price, - color = TangemTheme.colors.text.tertiary, - style = TangemTheme.typography.body2, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - modifier = Modifier - .weight(weight = 1f, fill = false), - ) - SpacerW(width = TangemTheme.dimens.spacing6) - TokenPriceChange(state = quotesState) - } - } -} - -@Composable -private fun Chart(quotes: QuotesState.Content) { - Box( - modifier = Modifier - .size(width = TangemTheme.dimens.size50, height = TangemTheme.dimens.size28), - ) { - PriceChangesChart(values = quotes.chartData) - } -} - -@Composable -private fun LoadingTokenItem(modifier: Modifier = Modifier) { - BaseSurface(modifier) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding( - horizontal = TangemTheme.dimens.spacing16, - vertical = TangemTheme.dimens.spacing4, - ), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), - ) { - CircleShimmer(modifier = Modifier.size(size = TangemTheme.dimens.size36)) - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween, - ) { - Column(verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing10)) { - RectangleShimmer( - modifier = Modifier.size( - width = TangemTheme.dimens.size70, - height = TangemTheme.dimens.size12, - ), - ) - RectangleShimmer( - modifier = Modifier.size( - width = TangemTheme.dimens.size52, - height = TangemTheme.dimens.size12, - ), - ) - } - RectangleShimmer( - modifier = Modifier.size( - width = TangemTheme.dimens.size46, - height = TangemTheme.dimens.size12, - ), - ) - } - } - } -} - -@Composable -private fun BaseSurface(modifier: Modifier = Modifier, content: @Composable () -> Unit) { - Surface( - modifier = modifier.defaultMinSize(minHeight = TOKEN_ITEM_HEIGHT), - color = TangemTheme.colors.background.primary, - ) { - content() - } -} - -// region Preview -@Preview(showBackground = true, widthDp = 360) -@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -private fun Preview_Tokens(@PreviewParameter(TokenConfigProvider::class) state: TokenItemState) { - TangemThemePreview { - TokenRowItem(state) - } -} - -private class TokenConfigProvider : CollectionPreviewParameterProvider( - collection = listOf( - TokenItemStatePreviewData.tokenLoading, - TokenItemStatePreviewData.loadedPriceDown, - TokenItemStatePreviewData.loadedPriceUp, - TokenItemStatePreviewData.loadedPriceNeutral, - ), -) -// endregion Preview \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokensList.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokensList.kt deleted file mode 100644 index ca26ef0621..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/TokensList.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.ui.components - -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.paging.LoadState -import androidx.paging.compose.LazyPagingItems -import com.tangem.core.ui.res.TangemTheme -import com.tangem.features.managetokens.impl.R -import com.tangem.managetokens.presentation.managetokens.state.AddCustomTokenButton -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState - -private const val PLACEHOLDER_ITEMS_COUNT = 50 - -@Composable -internal fun TokensList( - tokens: LazyPagingItems, - addCustomTokenButton: AddCustomTokenButton, - modifier: Modifier = Modifier, -) { - LazyColumn(modifier = modifier) { - item { - Text( - text = stringResource(id = R.string.manage_tokens_list_header_title), - style = TangemTheme.typography.h3, - color = TangemTheme.colors.text.primary1, - modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16), - ) - } - - if (tokens.loadState.refresh is LoadState.Loading) { - items(PLACEHOLDER_ITEMS_COUNT) { - TokenRowItem(state = TokenItemState.Loading(it.toString())) - } - } else { - val tokensList = tokens.itemSnapshotList - if (tokensList.isEmpty()) { - item { - Text( - text = stringResource(id = R.string.manage_tokens_nothing_found), - style = TangemTheme.typography.caption2, - color = TangemTheme.colors.text.tertiary, - modifier = Modifier.padding( - top = TangemTheme.dimens.spacing8, - start = TangemTheme.dimens.spacing16, - end = TangemTheme.dimens.spacing16, - ), - ) - } - } - - items(items = tokensList.items, key = TokenItemState::id) { token -> - TokenRowItem(state = token) - } - - if (addCustomTokenButton.isVisible) { - item { - AddCustomTokenButton(onButtonClick = addCustomTokenButton.onClick) - } - } - } - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensClickIntents.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensClickIntents.kt deleted file mode 100644 index 2b6ba5b3bd..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensClickIntents.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.viewmodels - -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState - -internal interface ManageTokensClickIntents { - - fun onAddCustomTokensButtonClick() - - fun onSearchQueryChange(query: String) - - fun onSearchActiveChange(active: Boolean) - - fun onTokenItemButtonClick(token: TokenItemState.Loaded) - - fun onGetAddressesClick() - - fun onBackClick() - - fun onCloseChooseNetworkScreen() - - fun onNetworkToggleClick(token: TokenItemState.Loaded, network: NetworkItemState.Toggleable) - - fun onNonNativeNetworkHintClick() - - fun onChooseWalletClick() - - fun onCloseChoosingWalletClick() - - fun onWalletSelected(walletId: String) -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensUiEvents.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensUiEvents.kt deleted file mode 100644 index 663871cf2a..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensUiEvents.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.viewmodels - -internal interface ManageTokensUiEvents { - - fun onEmptySearchResult(query: String) - - fun onAddCustomTokenSheetDismissed() -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensViewModel.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensViewModel.kt deleted file mode 100644 index caa5ca105b..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/viewmodels/ManageTokensViewModel.kt +++ /dev/null @@ -1,445 +0,0 @@ -package com.tangem.managetokens.presentation.managetokens.viewmodels - -import androidx.compose.runtime.* -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import androidx.paging.PagingData -import androidx.paging.map -import arrow.core.getOrElse -import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase -import com.tangem.domain.appcurrency.model.AppCurrency -import com.tangem.domain.card.DerivePublicKeysUseCase -import com.tangem.domain.common.util.derivationStyleProvider -import com.tangem.domain.tokens.* -import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.domain.wallets.models.UserWallet -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase -import com.tangem.domain.wallets.usecase.GetWalletsUseCase -import com.tangem.domain.wallets.usecase.SelectWalletUseCase -import com.tangem.features.managetokens.navigation.ExpandableState -import com.tangem.managetokens.presentation.common.analytics.ManageTokens -import com.tangem.managetokens.presentation.common.state.AlertState -import com.tangem.managetokens.presentation.common.state.Event -import com.tangem.managetokens.presentation.common.state.NetworkItemState -import com.tangem.managetokens.presentation.managetokens.state.ManageTokensState -import com.tangem.managetokens.presentation.managetokens.state.TokenButtonType -import com.tangem.managetokens.presentation.managetokens.state.TokenItemState -import com.tangem.managetokens.presentation.managetokens.state.factory.* -import com.tangem.utils.Provider -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import com.tangem.utils.coroutines.Debouncer -import com.tangem.utils.coroutines.Debouncer.Companion.DEFAULT_WAIT_TIME_MS -import com.tangem.utils.coroutines.JobHolder -import com.tangem.utils.coroutines.saveIn -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.* -import timber.log.Timber -import java.util.Collections -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.CopyOnWriteArrayList -import javax.inject.Inject -import kotlin.collections.set -import kotlin.properties.Delegates - -@Suppress("LongParameterList", "LargeClass") -@HiltViewModel -internal class ManageTokensViewModel @Inject constructor( - private val dispatchers: CoroutineDispatcherProvider, - private val getGlobalTokenListUseCase: GetGlobalTokenListUseCase, - private val getWalletsUseCase: GetWalletsUseCase, - private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, - private val removeCurrencyUseCase: RemoveCurrencyUseCase, - private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase, - private val selectWalletUseCase: SelectWalletUseCase, - private val getCurrenciesUseCase: GetCryptoCurrenciesUseCase, - private val derivePublicKeysUseCase: DerivePublicKeysUseCase, - private val getMissedAddressesCryptoCurrenciesUseCase: GetMissedAddressesCryptoCurrenciesUseCase, - private val fetchTokenListUseCase: FetchTokenListUseCase, - private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, - private val checkCurrencyCompatibilityUseCase: CheckCurrencyCompatibilityUseCase, - private val isCryptoCurrencyCoinCouldHide: IsCryptoCurrencyCoinCouldHideUseCase, - private val analyticsEventHandler: AnalyticsEventHandler, -) : ViewModel(), ManageTokensClickIntents, ManageTokensUiEvents { - - private val stateFactory = ManageTokensStateFactory( - currentStateProvider = Provider { uiState }, - clickIntents = this, - uiIntents = this, - ) - - var uiState: ManageTokensState by mutableStateOf(stateFactory.getInitialState(flowOf(PagingData.from(emptyList())))) - private set - - private var expandableState: ExpandableState = ExpandableState.COLLAPSED - - private val currenciesListJobHolder: JobHolder = JobHolder() - - private val debouncer = Debouncer() - - private var allAddedCurrencies: MutableList = Collections.synchronizedList( - mutableListOf(), - ) - - private var wallets: CopyOnWriteArrayList by Delegates.notNull() - - private var addedCurrenciesByWallet: MutableMap> = ConcurrentHashMap() - - private var selectedWallet: UserWallet? = null - - private var currenciesToGenerateAddresses: Map> = emptyMap() - - private val selectedAppCurrencyFlow: StateFlow = createSelectedAppCurrencyFlow() - - private val quotesStateConverter = QuotesToQuotesStateConverter() - - private val networkToNetworkItemStateConverter = NetworkToNetworkItemStateConverter( - addedCurrenciesByWalletProvider = Provider { addedCurrenciesByWallet }, - selectedWalletProvider = Provider { selectedWallet }, - onNetworkToggleClick = this::onNetworkToggleClick, - ) - - private val networksToChooseNetworkStateConverter = NetworksToChooseNetworkStateConverter( - networkToNetworkItemStateConverter = networkToNetworkItemStateConverter, - onNonNativeNetworkHintClick = this::onNonNativeNetworkHintClick, - onCloseChooseNetworkScreen = this::onCloseChooseNetworkScreen, - ) - - private val tokenConverter = TokenConverter( - quotesStateConverter = quotesStateConverter, - networksToChooseNetworkStateConverter = networksToChooseNetworkStateConverter, - allAddedCurrencies = Provider { allAddedCurrencies }, - selectedAppCurrency = Provider { selectedAppCurrencyFlow.value }, - onTokenItemButtonClick = this::onTokenItemButtonClick, - ) - - init { - analyticsEventHandler.send(ManageTokens.ScreenOpened()) - - viewModelScope.launch(dispatchers.io) { - getWalletsUseCase() - .distinctUntilChanged() - .collectLatest { userWallets -> - launch { - subscribeToCurrencies(userWallets) - }.saveIn(currenciesListJobHolder) - } - } - } - - fun setExpandableState(state: State) { - expandableState = state.value - } - - private suspend fun subscribeToCurrencies(userWallets: List) { - wallets = CopyOnWriteArrayList(userWallets.filter { it.isMultiCurrency && !it.isLocked }) - - combine(wallets.map { getCurrenciesUseCase.invoke(it.walletId).distinctUntilChanged() }) { - if (expandableState == ExpandableState.EXPANDED) return@combine - - allAddedCurrencies.clear() - addedCurrenciesByWallet.clear() - - val walletsWithCurrencies = wallets.zip( - it.map { currencyList -> - currencyList.getOrElse { - Timber.e("Couldn't retrieve currency list") - emptyList() - } - }, - ) - - allAddedCurrencies = walletsWithCurrencies.flatMap { it.second }.toMutableList() - - walletsWithCurrencies.forEach { (wallet, currencies) -> - addedCurrenciesByWallet[wallet] = currencies.toMutableList() - } - - withContext(dispatchers.main) { - uiState = uiState.copy(tokens = getInitialTokensList()) - } - selectedWallet = getSelectedWalletSyncUseCase().fold( - ifLeft = { null }, - ifRight = { if (!it.isMultiCurrency || it.isLocked) null else it }, - ) - if (selectedWallet == null && wallets.isNotEmpty()) { - selectWalletUseCase(wallets.first().walletId) - selectedWallet = wallets.first() - } - updateDerivationNotificationState() - withContext(dispatchers.main) { - uiState = stateFactory.updateChooseWalletState(wallets, userWallets, selectedWallet) - } - }.collect() - } - - private fun getInitialTokensList(searchText: String = ""): Flow> { - return getGlobalTokenListUseCase(searchText = searchText).map { - it.map { token -> tokenConverter.convert(token) } - } - } - - private fun updateDerivationNotificationState() { - viewModelScope.launch(dispatchers.io) { - getMissedAddressesCryptoCurrenciesUseCase(wallets.map { it.walletId }) - .distinctUntilChanged() - .collectLatest { - it.onRight { mapOfMissingDerivations -> - currenciesToGenerateAddresses = mapOfMissingDerivations - withContext(dispatchers.main) { updateDerivation() } - } - } - } - } - - private fun updateDerivation() { - val totalNeeded = currenciesToGenerateAddresses.values.sumOf { derivations -> derivations.size } - val walletsToDerive = currenciesToGenerateAddresses.values - .filter { derivations -> derivations.isNotEmpty() }.size - uiState = stateFactory.updateDerivationNotification( - totalNeeded = totalNeeded, - totalWallets = wallets.size, - walletsToDerive = walletsToDerive, - ) - } - - private fun createSelectedAppCurrencyFlow(): StateFlow { - return getSelectedAppCurrencyUseCase() - .map { maybeAppCurrency -> - maybeAppCurrency.getOrElse { AppCurrency.Default } - } - .stateIn( - scope = viewModelScope, - started = SharingStarted.Eagerly, - initialValue = AppCurrency.Default, - ) - } - - override fun onAddCustomTokensButtonClick() { - analyticsEventHandler.send(ManageTokens.ButtonCustomToken) - uiState = uiState.copy(customTokenBottomSheetConfig = uiState.customTokenBottomSheetConfig.copy(isShow = true)) - } - - override fun onSearchQueryChange(query: String) { - uiState = uiState.copy(searchBarState = uiState.searchBarState.copy(query = query)) - - debouncer.debounce(waitMs = DEFAULT_WAIT_TIME_MS, coroutineScope = viewModelScope + dispatchers.io) { - val state = stateFactory.showAddCustomTokensButton(query.isNotBlank()) - uiState = state.copy(tokens = getInitialTokensList(query)) - } - } - - override fun onSearchActiveChange(active: Boolean) { - uiState = uiState.copy(searchBarState = uiState.searchBarState.copy(active = active)) - } - - override fun onTokenItemButtonClick(token: TokenItemState.Loaded) { - when (token.availableAction.value) { - TokenButtonType.ADD, TokenButtonType.EDIT -> { - if (token.availableAction.value == TokenButtonType.ADD) { - analyticsEventHandler.send(ManageTokens.ButtonAdd(token.currencySymbol)) - } - if (token.availableAction.value == TokenButtonType.EDIT) { - analyticsEventHandler.send(ManageTokens.ButtonEdit(token.currencySymbol)) - } - - uiState = uiState.copy(selectedToken = token) - val addedCurrenciesOnWallet = addedCurrenciesByWallet[selectedWallet] ?: listOf() - stateFactory.updateTokenNetworksOnTokenSelection(token, addedCurrenciesOnWallet) - } - TokenButtonType.NOT_AVAILABLE -> { - uiState = stateFactory.getStateAndTriggerEvent( - state = uiState, - event = Event.ShowAlert( - AlertState.TokenUnavailable( - onUpvoteClick = {}, // TODO later, when endpoint is available - ), - ), - setUiState = { uiState = it }, - ) - } - } - } - - override fun onGetAddressesClick() { - if (currenciesToGenerateAddresses.isNotEmpty()) { - viewModelScope.launch(dispatchers.io) { - val cardCount = currenciesToGenerateAddresses.count { it.value.isNotEmpty() } - analyticsEventHandler.send(ManageTokens.ButtonGenerateAddresses(cardCount)) - - currenciesToGenerateAddresses.forEach { (walletId, currenciesToDerive) -> - if (currenciesToDerive.isNotEmpty()) { - derivePublicKeysUseCase(walletId, currenciesToDerive) - .onRight { - updateDerivationNotificationState() - fetchTokenListUseCase(userWalletId = walletId) - } - } - } - } - } - } - - override fun onBackClick() { - TODO("Not yet implemented") // TODO: implement if needed when custom tokens and bottom sheet is complete - } - - override fun onCloseChooseNetworkScreen() { - uiState = uiState.copy(selectedToken = null) - } - - override fun onNetworkToggleClick(token: TokenItemState.Loaded, network: NetworkItemState.Toggleable) { - val selectedWallet = selectedWallet ?: return - if (!selectedWallet.isMultiCurrency || selectedWallet.isLocked) return - - if (network.isAdded.value) { - analyticsEventHandler.send( - ManageTokens.TokenSwitcherChanged(token = token.currencySymbol, AnalyticsParam.OnOffState.Off), - ) - toggleToken(token, network, selectedWallet) - } else { - analyticsEventHandler.send( - ManageTokens.TokenSwitcherChanged(token = token.currencySymbol, AnalyticsParam.OnOffState.On), - ) - viewModelScope.launch(dispatchers.io) { - checkCompatibilityAndToggleToken(token, network, selectedWallet) - } - } - } - - private suspend fun checkCompatibilityAndToggleToken( - token: TokenItemState.Loaded, - network: NetworkItemState.Toggleable, - selectedWallet: UserWallet, - ) { - checkCurrencyCompatibilityUseCase( - networkId = network.id, - isMainNetwork = network.address == null, - userWalletId = selectedWallet.walletId, - ) - .fold( - ifLeft = { error -> - uiState = stateFactory.getStateAndTriggerEvent( - state = uiState, - event = Event.ShowAlert( - stateFactory.transformAddTokenErrorToAlert( - error, - network.name, - ), - ), - setUiState = { uiState = it }, - ) - }, - ifRight = { - withContext(dispatchers.main) { toggleToken(token, network, selectedWallet) } - }, - ) - } - - private fun toggleToken( - token: TokenItemState.Loaded, - network: NetworkItemState.Toggleable, - selectedWallet: UserWallet, - ) { - val cryptoCurrency = requireNotNull( - TokenToCryptoCurrencyConverter( - network = network, - derivationStyleProvider = selectedWallet.scanResponse.derivationStyleProvider, - ).convert(token), - ) { - "It is only null if Blockchain is Unknown, which mustn't happen here" - } - if (!network.isAdded.value) { - addedCurrenciesByWallet[selectedWallet]?.add(cryptoCurrency) - allAddedCurrencies.add(cryptoCurrency) - viewModelScope.launch(dispatchers.io) { - addCryptoCurrenciesUseCase( - userWalletId = selectedWallet.walletId, - currency = cryptoCurrency, - ) - } - updateUi(token, network) - } else { - viewModelScope.launch(dispatchers.io) { - if (canBeRemovedAndShowAlertIfNot(selectedWallet.walletId, cryptoCurrency)) { - addedCurrenciesByWallet[selectedWallet]?.remove(cryptoCurrency) - allAddedCurrencies.remove(cryptoCurrency) - removeCurrencyUseCase(selectedWallet.walletId, cryptoCurrency) - withContext(dispatchers.main) { updateUi(token, network) } - } - } - } - } - - private fun updateUi(token: TokenItemState.Loaded, network: NetworkItemState.Toggleable) { - stateFactory.toggleNetworkState(token, network, allAddedCurrencies) - updateDerivationNotificationState() - } - - private suspend fun canBeRemovedAndShowAlertIfNot( - walletId: UserWalletId, - cryptoCurrency: CryptoCurrency, - ): Boolean { - return if (cryptoCurrency is CryptoCurrency.Coin && - !isCryptoCurrencyCoinCouldHide(walletId, cryptoCurrency) - ) { - uiState = stateFactory.getStateAndTriggerEvent( - state = uiState, - event = Event.ShowAlert( - AlertState.CannotHideNetworkWithTokens( - tokenName = cryptoCurrency.name, - currencySymbol = cryptoCurrency.symbol, - networkName = cryptoCurrency.network.name, - ), - ), - setUiState = { uiState = it }, - ) - false - } else { - true - } - } - - override fun onNonNativeNetworkHintClick() { - analyticsEventHandler.send(ManageTokens.NoticeNonNativeNetworkClicked) - uiState = stateFactory.getStateAndTriggerEvent( - state = uiState, - event = Event.ShowAlert(AlertState.NonNative), - setUiState = { uiState = it }, - ) - } - - override fun onChooseWalletClick() { - analyticsEventHandler.send(ManageTokens.ButtonChooseWallet) - uiState = uiState.copy( - showChooseWalletScreen = true, - ) - } - - override fun onCloseChoosingWalletClick() { - uiState = uiState.copy( - showChooseWalletScreen = false, - ) - } - - override fun onWalletSelected(walletId: String) { - analyticsEventHandler.send(ManageTokens.WalletSelected(ManageTokens.WalletSelected.Source.MainToken)) - viewModelScope.launch(dispatchers.io) { - selectWalletUseCase(UserWalletId(walletId)) - } - selectedWallet = wallets.find { it.walletId.stringValue == walletId } - uiState.selectedToken?.let { onTokenItemButtonClick(it) } - uiState = stateFactory.updateSelectedWallet(selectedWalletId = selectedWallet?.walletId?.stringValue) - } - - override fun onEmptySearchResult(query: String) { - analyticsEventHandler.send(ManageTokens.TokenIsNotFound(query)) - } - - override fun onAddCustomTokenSheetDismissed() { - uiState = uiState.copy(customTokenBottomSheetConfig = uiState.customTokenBottomSheetConfig.copy(isShow = false)) - } -} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/router/ManageTokensUiImpl.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/router/ManageTokensUiImpl.kt deleted file mode 100644 index 9bcf70872f..0000000000 --- a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/router/ManageTokensUiImpl.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.managetokens.presentation.router - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.State -import androidx.compose.ui.unit.Dp -import androidx.hilt.navigation.compose.hiltViewModel -import com.tangem.features.managetokens.navigation.ExpandableState -import com.tangem.features.managetokens.navigation.ManageTokensUi -import com.tangem.managetokens.presentation.managetokens.ui.ManageTokensScreen -import com.tangem.managetokens.presentation.managetokens.viewmodels.ManageTokensViewModel -import javax.inject.Inject - -internal class ManageTokensUiImpl @Inject constructor() : ManageTokensUi { - - @Composable - override fun Content(onHeaderSizeChange: (Dp) -> Unit, state: State) { - val viewModel = hiltViewModel() - viewModel.setExpandableState(state) - - ManageTokensScreen( - state = viewModel.uiState, - onHeaderSizeChange = onHeaderSizeChange, - ) - } -} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt index 6535806903..7c3629f145 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt @@ -5,7 +5,6 @@ import androidx.compose.ui.Modifier import com.tangem.core.ui.UiDependencies import com.tangem.core.ui.screen.ComposeFragment import com.tangem.feature.wallet.presentation.router.InnerWalletRouter -import com.tangem.features.managetokens.navigation.ManageTokensUi import com.tangem.features.wallet.navigation.WalletRouter import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @@ -21,9 +20,6 @@ internal class WalletFragment : ComposeFragment() { @Inject override lateinit var uiDependencies: UiDependencies - @Inject - internal lateinit var manageTokensUi: ManageTokensUi - /** Feature router */ @Inject internal lateinit var walletRouter: WalletRouter @@ -37,7 +33,6 @@ internal class WalletFragment : ComposeFragment() { override fun ScreenContent(modifier: Modifier) { _walletRouter.Initialize( onFinish = requireActivity()::finish, - manageTokensUi = manageTokensUi, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt index 509a1b3085..5397088c1e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt @@ -1,6 +1,5 @@ package com.tangem.feature.wallet.presentation.common.preview -import androidx.compose.runtime.mutableStateOf import com.tangem.core.ui.components.currency.tokenicon.TokenIconState import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.core.ui.event.consumedEvent @@ -12,7 +11,6 @@ import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.common.WalletPreviewData.topBarConfig import com.tangem.feature.wallet.presentation.common.state.TokenItemState import com.tangem.feature.wallet.presentation.wallet.state.model.* -import com.tangem.features.managetokens.navigation.ExpandableState import kotlinx.collections.immutable.persistentListOf internal object WalletScreenPreviewData { @@ -151,7 +149,6 @@ internal object WalletScreenPreviewData { internal val walletScreenState = WalletScreenState( onBackClick = {}, - manageTokensExpandableState = mutableStateOf(ExpandableState.COLLAPSED), topBarConfig = topBarConfig, selectedWalletIndex = 0, wallets = persistentListOf( @@ -161,6 +158,5 @@ internal object WalletScreenPreviewData { onWalletChange = {}, event = consumedEvent(), isHidingMode = false, - manageTokenRedesignToggle = false, ) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index 292cea1bde..815f0493b4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -1,9 +1,9 @@ package com.tangem.feature.wallet.presentation.router import android.annotation.SuppressLint -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.unit.dp import androidx.fragment.app.Fragment import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -25,8 +25,6 @@ import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensScree import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensViewModel import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletViewModel -import com.tangem.features.managetokens.navigation.ExpandableState -import com.tangem.features.managetokens.navigation.ManageTokensUi import kotlin.properties.Delegates /** Default implementation of wallet feature router */ @@ -42,7 +40,7 @@ internal class DefaultWalletRouter( override fun getEntryFragment(): Fragment = WalletFragment.create() @Composable - override fun Initialize(onFinish: () -> Unit, manageTokensUi: ManageTokensUi) { + override fun Initialize(onFinish: () -> Unit) { this.onFinish = onFinish NavHost( @@ -55,20 +53,8 @@ internal class DefaultWalletRouter( subscribeToLifecycle(LocalLifecycleOwner.current) } - var bottomSheetHeaderHeight by remember { mutableStateOf(0.dp) } - WalletScreen( state = viewModel.uiState.collectAsStateWithLifecycle().value, - bottomSheetHeaderHeightProvider = { bottomSheetHeaderHeight }, - bottomSheetContent = { - val state = remember { mutableStateOf(ExpandableState.COLLAPSED) } - // Manage Tokens - manageTokensUi.Content( - onHeaderSizeChange = { bottomSheetHeaderHeight = it }, - state = state, - ) - viewModel.setExpandableState(state) - }, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt index 6b05b626ce..d213d227f8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt @@ -2,10 +2,8 @@ package com.tangem.feature.wallet.presentation.router import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable - import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.features.managetokens.navigation.ManageTokensUi import com.tangem.features.wallet.navigation.WalletRouter /** @@ -26,7 +24,7 @@ internal interface InnerWalletRouter : WalletRouter { */ @Suppress("TopLevelComposableFunctions") @Composable - fun Initialize(onFinish: () -> Unit, manageTokensUi: ManageTokensUi) + fun Initialize(onFinish: () -> Unit) /** Pop back stack */ fun popBackStack() diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateController.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateController.kt index e8c3c9114c..af25a1257b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateController.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateController.kt @@ -1,6 +1,5 @@ package com.tangem.feature.wallet.presentation.wallet.state -import androidx.compose.runtime.mutableStateOf import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent import com.tangem.core.ui.event.consumedEvent import com.tangem.domain.wallets.models.UserWalletId @@ -11,8 +10,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTopBarCon import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBottomSheetTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.OpenBottomSheetTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.WalletScreenStateTransformer -import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles -import com.tangem.features.managetokens.navigation.ExpandableState import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -26,9 +23,7 @@ import javax.inject.Singleton [REDACTED_AUTHOR] */ @Singleton -internal class WalletStateController @Inject constructor( - private val manageTokensFeatureToggles: ManageTokensFeatureToggles, -) { +internal class WalletStateController @Inject constructor() { val uiState: StateFlow get() = mutableUiState @@ -87,8 +82,6 @@ internal class WalletStateController @Inject constructor( onWalletChange = {}, event = consumedEvent(), isHidingMode = false, - manageTokenRedesignToggle = manageTokensFeatureToggles.isRedesignedScreenEnabled, - manageTokensExpandableState = mutableStateOf(ExpandableState.EXPANDED), ) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletScreenState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletScreenState.kt index 5c9424f9ee..9285575d9e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletScreenState.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletScreenState.kt @@ -1,18 +1,14 @@ package com.tangem.feature.wallet.presentation.wallet.state.model -import androidx.compose.runtime.MutableState import com.tangem.core.ui.event.StateEvent -import com.tangem.features.managetokens.navigation.ExpandableState import kotlinx.collections.immutable.ImmutableList internal data class WalletScreenState( val onBackClick: () -> Unit, - val manageTokensExpandableState: MutableState, val topBarConfig: WalletTopBarConfig, val selectedWalletIndex: Int, val wallets: ImmutableList, val onWalletChange: (Int) -> Unit, val event: StateEvent, val isHidingMode: Boolean, - val manageTokenRedesignToggle: Boolean, ) \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt index 0a72f0cf4e..0de613caa1 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt @@ -2,11 +2,6 @@ package com.tangem.feature.wallet.presentation.wallet.ui import android.content.res.Configuration import androidx.activity.compose.BackHandler -import androidx.compose.animation.core.TweenSpec -import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.foundation.Canvas -import androidx.compose.foundation.background -import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListScope @@ -15,28 +10,22 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState -import androidx.compose.material3.* +import androidx.compose.material3.FabPosition +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.luminance -import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp import androidx.paging.compose.collectAsLazyPagingItems -import com.google.accompanist.systemuicontroller.rememberSystemUiController -import com.tangem.core.ui.components.* -import com.tangem.core.ui.components.atoms.Hand -import com.tangem.core.ui.components.atoms.handComposableComponentHeight +import com.tangem.core.ui.components.BottomFade +import com.tangem.core.ui.components.PrimaryButton import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBottomSheet import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBottomSheetConfig @@ -66,16 +55,10 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.VisaTxDe import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.balancesAndLimitsBlock import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.depositButton import com.tangem.feature.wallet.presentation.wallet.ui.utils.changeWalletAnimator -import com.tangem.features.managetokens.navigation.ExpandableState import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.launch @Composable -internal fun WalletScreen( - state: WalletScreenState, - bottomSheetHeaderHeightProvider: () -> Dp, - bottomSheetContent: @Composable () -> Unit, -) { +internal fun WalletScreen(state: WalletScreenState) { BackHandler(onBack = state.onBackClick) // It means that screen is still initializing @@ -98,9 +81,6 @@ internal fun WalletScreen( snackbarHostState = snackbarHostState, isAutoScroll = isAutoScroll, onAutoScrollReset = { isAutoScroll.value = false }, - bottomSheetHeaderHeightProvider = bottomSheetHeaderHeightProvider, - bottomSheetContent = bottomSheetContent, - alertConfig = alertConfig, ) WalletEventEffect( @@ -120,10 +100,7 @@ private fun WalletContent( walletsListState: LazyListState, snackbarHostState: SnackbarHostState, isAutoScroll: State, - bottomSheetHeaderHeightProvider: () -> Dp, onAutoScrollReset: () -> Unit, - bottomSheetContent: @Composable () -> Unit, - alertConfig: WalletAlertState?, ) { var selectedWalletIndex by remember(state.selectedWalletIndex) { mutableIntStateOf(state.selectedWalletIndex) } val selectedWallet = state.wallets.getOrElse(selectedWalletIndex) { state.wallets[state.selectedWalletIndex] } @@ -218,282 +195,12 @@ private fun WalletContent( ) } - if (state.manageTokenRedesignToggle) { - BaseScaffoldManageTokenRedesign( - state = state, - selectedWallet = selectedWallet, - snackbarHostState = snackbarHostState, - bottomSheetHeaderHeightProvider = bottomSheetHeaderHeightProvider, - bottomSheetContent = bottomSheetContent, - alertConfig = alertConfig, - ) { - scaffoldContent() - } - } else { - BaseScaffold( - state = state, - selectedWallet = selectedWallet, - snackbarHostState = snackbarHostState, - ) { - scaffoldContent() - } - } -} - -@Suppress("LongParameterList", "LongMethod") -@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class) -@Composable -private fun BaseScaffoldManageTokenRedesign( - state: WalletScreenState, - selectedWallet: WalletState, - snackbarHostState: SnackbarHostState, - bottomSheetHeaderHeightProvider: () -> Dp, - bottomSheetContent: @Composable () -> Unit, - alertConfig: WalletAlertState?, - content: @Composable () -> Unit, -) { - // show the bottom sheet if there is at least one multicurrency wallet - val showManageTokensBottomSheet = remember(state.wallets) { - state.wallets.any { it is WalletState.MultiCurrency } - } - val bottomSheetState = rememberSheetStateEnhanced( - initialValue = if (showManageTokensBottomSheet) SheetValue.PartiallyExpanded else SheetValue.Hidden, - confirmValueChange = { sheetValue -> - when { - sheetValue == SheetValue.Hidden && showManageTokensBottomSheet -> false - sheetValue != SheetValue.Hidden && !showManageTokensBottomSheet -> false - else -> true - } - }, - skipHiddenState = showManageTokensBottomSheet, - ) - - val keyboardShown = keyboardAsState() - - BottomSheetStateEffects( - bottomSheetState = bottomSheetState, + BaseScaffold( state = state, - showManageTokensBottomSheet = showManageTokensBottomSheet, - alertConfig = alertConfig, - keyboardShown = keyboardShown, - ) - - val scaffoldState = rememberBottomSheetScaffoldState( - bottomSheetState = bottomSheetState, + selectedWallet = selectedWallet, snackbarHostState = snackbarHostState, - ) - - val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() } - val statusBarHeight = with(LocalDensity.current) { WindowInsets.statusBars.getTop(this).toDp() } - val peekHeight = bottomSheetHeaderHeightProvider() + handComposableComponentHeight + bottomBarHeight - - val coroutineScope = rememberCoroutineScope() - - BottomSheetScaffold( - snackbarHost = { - WalletSnackbarHost( - snackbarHostState = it, - event = state.event, - modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing16), - ) - }, - containerColor = TangemTheme.colors.background.secondary, - sheetContainerColor = TangemTheme.colors.background.primary, - scaffoldState = scaffoldState, - sheetPeekHeight = peekHeight, - sheetDragHandle = { - Hand(modifier = Modifier.background(color = TangemTheme.colors.background.primary)) - }, - sheetContent = { - BoxWithConstraints { - Box( - modifier = Modifier - .sizeIn(maxHeight = maxHeight - statusBarHeight) - .align(Alignment.BottomCenter), - ) { - bottomSheetContent() - } - } - - // hide bottom sheet when back pressed - BackHandler( - keyboardShown.value is Keyboard.Closed && - bottomSheetState.currentValue == SheetValue.Expanded, - ) { - coroutineScope.launch { bottomSheetState.partialExpand() } - } - }, - content = { _ -> - val pullRefreshState = rememberPullRefreshState( - refreshing = selectedWallet.pullToRefreshConfig.isRefreshing, - onRefresh = { - selectedWallet.pullToRefreshConfig.onRefresh(WalletPullToRefreshConfig.ShowRefreshState(true)) - }, - ) - - Column { - WalletTopBar(config = state.topBarConfig) - Box( - modifier = Modifier.pullRefresh(pullRefreshState), - ) { - content() - - WalletPullToRefreshIndicator( - isRefreshing = selectedWallet.pullToRefreshConfig.isRefreshing, - state = pullRefreshState, - modifier = Modifier.align(Alignment.TopCenter), - ) - } - } - - BottomSheetScrim( - color = BottomSheetDefaults.ScrimColor, - visible = bottomSheetState.targetValue == SheetValue.Expanded, - onDismissRequest = { coroutineScope.launch { bottomSheetState.partialExpand() } }, - ) - }, - ) -} - -@Composable -private fun BottomSheetScrim(color: Color, visible: Boolean, onDismissRequest: () -> Unit) { - val alpha by animateFloatAsState( - targetValue = if (visible) 1f else 0f, - animationSpec = TweenSpec(), - label = "scrim", - ) - val dismissSheet = if (visible) { - Modifier - .pointerInput(onDismissRequest) { - detectTapGestures { - onDismissRequest() - } - } - .clearAndSetSemantics {} - } else { - Modifier - } - Canvas( - Modifier - .fillMaxSize() - .then(dismissSheet), ) { - drawRect(color = color, alpha = alpha) - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Suppress("CyclomaticComplexMethod", "MagicNumber") -@Composable -private fun BottomSheetStateEffects( - bottomSheetState: SheetState, - state: WalletScreenState, - showManageTokensBottomSheet: Boolean, - alertConfig: WalletAlertState?, - keyboardShown: State, -) { - // Bottom sheet during initialization internally expand partially after its content was remeasured, - // therefore initialValue = SheetValue.Hidden in rememberStandardBottomSheetState doesn't work as expected - // so we have to manually restrict expansion in this case - LaunchedEffect(bottomSheetState.targetValue, bottomSheetState.currentValue) { - if (!showManageTokensBottomSheet && - (bottomSheetState.targetValue != SheetValue.Hidden || bottomSheetState.currentValue != SheetValue.Hidden) - ) { - bottomSheetState.hide() - } - } - // react to changes in wallet list - LaunchedEffect(showManageTokensBottomSheet) { - when { - showManageTokensBottomSheet && bottomSheetState.currentValue != SheetValue.PartiallyExpanded -> { - bottomSheetState.partialExpand() - } - !showManageTokensBottomSheet && bottomSheetState.targetValue != SheetValue.Hidden -> { - bottomSheetState.hide() - } - } - } - - val systemUiController = rememberSystemUiController() - val navigationBarColor = TangemTheme.colors.background.primary - - LaunchedEffect(key1 = bottomSheetState.targetValue, navigationBarColor) { - when (bottomSheetState.targetValue) { - SheetValue.Hidden, - SheetValue.Expanded, - -> systemUiController.setNavigationBarColor( - color = Color.Transparent, - darkIcons = navigationBarColor.luminance() > 0.5f, - navigationBarContrastEnforced = true, - ) - SheetValue.PartiallyExpanded, - -> systemUiController.setNavigationBarColor(navigationBarColor) - } - } - - DisposableEffect(showManageTokensBottomSheet) { - onDispose { - if (showManageTokensBottomSheet) { - systemUiController.setNavigationBarColor( - color = Color.Transparent, - darkIcons = navigationBarColor.luminance() > 0.5f, - navigationBarContrastEnforced = false, - ) - } - } - } - - // expand bottom sheet when keyboard appears - LaunchedEffect(keyboardShown.value is Keyboard.Opened) { - if (keyboardShown.value is Keyboard.Opened && alertConfig == null) { - bottomSheetState.expand() - } - } - - val keyboardController = LocalSoftwareKeyboardController.current - // hide keyboard when bottom sheet is about to be hidden - LaunchedEffect(Unit) { - snapshotFlow { - bottomSheetState.currentValue == SheetValue.Expanded && - bottomSheetState.targetValue == SheetValue.PartiallyExpanded - }.collect { sheetHasBeenHidden -> - if (sheetHasBeenHidden) { - keyboardController?.hide() - } - } - } - - val isSheetHidden = bottomSheetState.targetValue == SheetValue.PartiallyExpanded - LaunchedEffect(isSheetHidden) { - if (isSheetHidden) { - state.manageTokensExpandableState.value = ExpandableState.COLLAPSED - } else { - state.manageTokensExpandableState.value = ExpandableState.EXPANDED - } - } -} - -/** - * Use a standard method when this is fixed https://issuetracker.google.com/issues/314796718 - * Current material3 version: 1.2.0 - */ -@Composable -@ExperimentalMaterial3Api -private fun rememberSheetStateEnhanced( - skipPartiallyExpanded: Boolean = false, - confirmValueChange: (SheetValue) -> Boolean = { true }, - initialValue: SheetValue = SheetValue.Hidden, - skipHiddenState: Boolean = false, -): SheetState { - val density = LocalDensity.current - return remember(initialValue, skipPartiallyExpanded, confirmValueChange, skipHiddenState) { - SheetState( - skipPartiallyExpanded = skipPartiallyExpanded, - density = density, - initialValue = initialValue, - confirmValueChange = confirmValueChange, - skipHiddenState = skipHiddenState, - ) + scaffoldContent() } } @@ -621,8 +328,6 @@ private fun WalletScreen_Preview(@PreviewParameter(WalletScreenPreviewProvider:: TangemThemePreview { WalletScreen( state = data, - bottomSheetHeaderHeightProvider = { 0.dp }, - bottomSheetContent = {}, ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index 8a7bf1d28d..5a63ee153a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -1,6 +1,5 @@ package com.tangem.feature.wallet.presentation.wallet.viewmodels -import androidx.compose.runtime.MutableState import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -28,7 +27,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.* import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents -import com.tangem.features.managetokens.navigation.ExpandableState import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION import com.tangem.utils.Provider import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -100,12 +98,6 @@ internal class WalletViewModel @Inject constructor( clickIntents.initialize(router, viewModelScope) } - fun setExpandableState(state: MutableState) { - stateHolder.update { - it.copy(manageTokensExpandableState = state) - } - } - fun subscribeToLifecycle(lifecycleOwner: LifecycleOwner) { lifecycleOwner.lifecycle.addObserver(screenLifecycleProvider) }