From a714868eb3072d10c6e29bfa6a9e9d76b00ccceb Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 17 Oct 2024 11:25:53 +0200 Subject: [PATCH 01/78] Portfolio View asset list --- .../nova/common/data/model/AssetViewMode.kt | 12 ++ .../repository/AssetsViewModeRepository.kt | 47 +++++ .../nova/common/di/CommonApi.kt | 3 + .../nova/common/di/modules/CommonModule.kt | 6 + .../nova/common/utils/TokenSymbol.kt | 6 + common/src/main/res/anim/asset_mode_in.xml | 8 + common/src/main/res/anim/asset_mode_out.xml | 8 + .../res/drawable/ic_asset_view_networks.xml | 14 ++ .../res/drawable/ic_asset_view_tokens.xml | 14 ++ common/src/main/res/values/strings.xml | 3 + .../di/AssetsFeatureDependencies.kt | 3 + .../feature_assets/domain/WalletInteractor.kt | 13 +- .../domain/WalletInteractorImpl.kt | 18 +- .../assets/list/AssetsListInteractor.kt | 11 +- .../assets/search/AssetSearchInteractor.kt | 18 +- .../domain/common/AssetPrefixNormalizing.kt | 26 +++ ...AssetSorting.kt => NetworkAssetSorting.kt} | 31 +-- .../domain/common/TokenAssetSorting.kt | 74 ++++++++ .../common/TotalAndTransferableBalance.kt | 33 ++++ .../balance/common/AssetGroupingDecoration.kt | 23 ++- .../balance/common/AssetListMixin.kt | 105 +++++++++++ .../balance/common/BalanceListAdapter.kt | 176 ++++++++---------- .../holders/NetworkAssetGroupViewHolder.kt | 17 ++ .../common/holders/NetworkAssetViewHolder.kt | 53 ++++++ .../holders/TokenAssetGroupViewHolder.kt | 50 +++++ .../common/holders/TokenAssetViewHolder.kt | 39 ++++ .../common/mappers/AssetMappersCommon.kt | 29 +++ .../NetworkAssetMappers.kt} | 76 ++++---- .../common/mappers/TokenAssetMappers.kt | 52 ++++++ .../balance/detail/BalanceDetailViewModel.kt | 2 +- .../balance/list/BalanceListFragment.kt | 13 +- .../balance/list/BalanceListViewModel.kt | 36 ++-- .../balance/list/di/BalanceListModule.kt | 29 ++- .../balance/list/model/items/AssetRvItem.kt | 13 ++ .../list/model/items/NetworkAssetUi.kt | 8 + .../NetworkGroupUi.kt} | 9 +- .../balance/list/model/items/TokenAssetUi.kt | 10 + .../balance/list/model/items/TokenGroupUi.kt | 15 ++ .../balance/list/view/AssetViewModeView.kt | 56 ++++++ .../balance/list/view/AssetsHeaderAdapter.kt | 25 ++- .../balance/search/AssetSearchFragment.kt | 5 + .../balance/search/AssetSearchViewModel.kt | 2 +- .../buy/flow/AssetBuyFlowFragment.kt | 5 + .../buy/flow/AssetBuyFlowViewModel.kt | 4 +- .../presentation/flow/AssetFlowViewModel.kt | 11 +- .../receive/flow/AssetReceiveFlowFragment.kt | 5 + .../receive/flow/AssetReceiveFlowViewModel.kt | 4 +- .../send/flow/AssetSendFlowFragment.kt | 5 + .../send/flow/AssetSendFlowViewModel.kt | 12 +- .../swap/AssetSwapFlowFragment.kt | 5 + .../swap/AssetSwapFlowViewModel.kt | 12 +- .../res/layout/fragment_asset_flow_search.xml | 2 +- .../main/res/layout/fragment_asset_search.xml | 2 +- .../main/res/layout/fragment_balance_list.xml | 2 +- .../src/main/res/layout/item_asset_header.xml | 10 +- ...{item_asset.xml => item_network_asset.xml} | 0 ...group.xml => item_network_asset_group.xml} | 0 .../src/main/res/layout/item_token_asset.xml | 98 ++++++++++ .../res/layout/item_token_asset_group.xml | 94 ++++++++++ .../main/res/layout/view_asset_view_mode.xml | 23 +++ .../nova/runtime/ext/TokenSorting.kt | 18 ++ 61 files changed, 1254 insertions(+), 249 deletions(-) create mode 100644 common/src/main/java/io/novafoundation/nova/common/data/model/AssetViewMode.kt create mode 100644 common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt create mode 100644 common/src/main/res/anim/asset_mode_in.xml create mode 100644 common/src/main/res/anim/asset_mode_out.xml create mode 100644 common/src/main/res/drawable/ic_asset_view_networks.xml create mode 100644 common/src/main/res/drawable/ic_asset_view_tokens.xml create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetPrefixNormalizing.kt rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/{AssetSorting.kt => NetworkAssetSorting.kt} (80%) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TotalAndTransferableBalance.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/{AssetMappers.kt => mappers/NetworkAssetMappers.kt} (50%) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/{AssetGroupUi.kt => items/NetworkGroupUi.kt} (64%) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt rename feature-assets/src/main/res/layout/{item_asset.xml => item_network_asset.xml} (100%) rename feature-assets/src/main/res/layout/{item_asset_group.xml => item_network_asset_group.xml} (100%) create mode 100644 feature-assets/src/main/res/layout/item_token_asset.xml create mode 100644 feature-assets/src/main/res/layout/item_token_asset_group.xml create mode 100644 feature-assets/src/main/res/layout/view_asset_view_mode.xml create mode 100644 runtime/src/main/java/io/novafoundation/nova/runtime/ext/TokenSorting.kt diff --git a/common/src/main/java/io/novafoundation/nova/common/data/model/AssetViewMode.kt b/common/src/main/java/io/novafoundation/nova/common/data/model/AssetViewMode.kt new file mode 100644 index 0000000000..04a0870730 --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/data/model/AssetViewMode.kt @@ -0,0 +1,12 @@ +package io.novafoundation.nova.common.data.model + +enum class AssetViewMode { + TOKENS, NETWORKS +} + +fun AssetViewMode.switch(): AssetViewMode { + return when (this) { + AssetViewMode.TOKENS -> AssetViewMode.NETWORKS + AssetViewMode.NETWORKS -> AssetViewMode.TOKENS + } +} diff --git a/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt b/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt new file mode 100644 index 0000000000..d1438523eb --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt @@ -0,0 +1,47 @@ +package io.novafoundation.nova.common.data.repository + +import io.novafoundation.nova.common.data.model.AssetViewMode +import io.novafoundation.nova.common.data.storage.Preferences +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext + +interface AssetsViewModeRepository { + fun assetsViewModeFlow(): Flow + suspend fun setAssetsViewMode(assetsViewMode: AssetViewMode) +} + +private const val PREFS_ASSETS_VIEW_MODE = "PREFS_ASSETS_VIEW_MODE" +private val ASSET_VIEW_MODE_DEFAULT = AssetViewMode.TOKENS + +class RealAssetsViewModeRepository( + private val preferences: Preferences +) : AssetsViewModeRepository { + + override fun assetsViewModeFlow(): Flow { + return preferences.stringFlow(PREFS_ASSETS_VIEW_MODE) + .map { + it?.fromPrefsValue() ?: ASSET_VIEW_MODE_DEFAULT + } + } + + override suspend fun setAssetsViewMode(assetsViewMode: AssetViewMode) = withContext(Dispatchers.IO) { + preferences.putString(PREFS_ASSETS_VIEW_MODE, assetsViewMode.toPrefsValue()) + } + + private fun AssetViewMode.toPrefsValue(): String { + return when (this) { + AssetViewMode.NETWORKS -> "networks" + AssetViewMode.TOKENS -> "tokens" + } + } + + private fun String.fromPrefsValue(): AssetViewMode? { + return when (this) { + "networks" -> AssetViewMode.NETWORKS + "tokens" -> AssetViewMode.TOKENS + else -> null + } + } +} diff --git a/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt b/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt index 9c52fe3e0e..0da563e315 100644 --- a/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt +++ b/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt @@ -14,6 +14,7 @@ import io.novafoundation.nova.common.data.network.HttpExceptionHandler import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser import io.novafoundation.nova.common.data.network.rpc.SocketSingleRequestExecutor +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1 import io.novafoundation.nova.common.data.secrets.v2.SecretStoreV2 @@ -154,6 +155,8 @@ interface CommonApi { fun buildTypeProvider(): BuildTypeProvider + fun assetsViewModeRepository(): AssetsViewModeRepository + val systemCallExecutor: SystemCallExecutor val actionAwaitableMixinFactory: ActionAwaitableMixin.Factory diff --git a/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt b/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt index 8de4f7e85f..3715d0f894 100644 --- a/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt +++ b/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt @@ -19,7 +19,9 @@ import io.novafoundation.nova.common.data.RealGoogleApiAvailabilityProvider import io.novafoundation.nova.common.data.memory.ComputationalCache import io.novafoundation.nova.common.data.memory.RealComputationalCache import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository +import io.novafoundation.nova.common.data.repository.RealAssetsViewModeRepository import io.novafoundation.nova.common.data.repository.RealBannerVisibilityRepository import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1 import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1Impl @@ -347,4 +349,8 @@ class CommonModule { fun provideCoinGeckoLinkParser(): CoinGeckoLinkParser { return CoinGeckoLinkParser() } + + @Provides + @ApplicationScope + fun assetsViewModeRepository(preferences: Preferences): AssetsViewModeRepository = RealAssetsViewModeRepository(preferences) } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/TokenSymbol.kt b/common/src/main/java/io/novafoundation/nova/common/utils/TokenSymbol.kt index 24af37c2c6..624e0194bb 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/TokenSymbol.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/TokenSymbol.kt @@ -7,11 +7,17 @@ import java.math.RoundingMode @JvmInline value class TokenSymbol(val value: String) { + companion object; // extensions + override fun toString() = value } fun String.asTokenSymbol() = TokenSymbol(this) +fun BigDecimal.formatTokenAmount(roundingMode: RoundingMode = RoundingMode.FLOOR): String { + return format(roundingMode) +} + fun BigDecimal.formatTokenAmount(tokenSymbol: TokenSymbol, roundingMode: RoundingMode = RoundingMode.FLOOR): String { return format(roundingMode).withTokenSymbol(tokenSymbol) } diff --git a/common/src/main/res/anim/asset_mode_in.xml b/common/src/main/res/anim/asset_mode_in.xml new file mode 100644 index 0000000000..abae8cfc27 --- /dev/null +++ b/common/src/main/res/anim/asset_mode_in.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/common/src/main/res/anim/asset_mode_out.xml b/common/src/main/res/anim/asset_mode_out.xml new file mode 100644 index 0000000000..320b08d13d --- /dev/null +++ b/common/src/main/res/anim/asset_mode_out.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/common/src/main/res/drawable/ic_asset_view_networks.xml b/common/src/main/res/drawable/ic_asset_view_networks.xml new file mode 100644 index 0000000000..d96811e9b4 --- /dev/null +++ b/common/src/main/res/drawable/ic_asset_view_networks.xml @@ -0,0 +1,14 @@ + + + + diff --git a/common/src/main/res/drawable/ic_asset_view_tokens.xml b/common/src/main/res/drawable/ic_asset_view_tokens.xml new file mode 100644 index 0000000000..b4a235b52e --- /dev/null +++ b/common/src/main/res/drawable/ic_asset_view_tokens.xml @@ -0,0 +1,14 @@ + + + + diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index 862440d046..6659575291 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -1,6 +1,9 @@ + Tokens + Networks + Wiki & Help Center Get support via Email diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt index 1ce1f7e787..5349c07576 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt @@ -10,6 +10,7 @@ import io.novafoundation.nova.common.data.network.AppLinksProvider import io.novafoundation.nova.common.data.network.HttpExceptionHandler import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.data.storage.encrypt.EncryptedPreferences @@ -169,6 +170,8 @@ interface AssetsFeatureDependencies { fun coingeckoApi(): CoingeckoApi + fun assetsViewModeRepository(): AssetsViewModeRepository + fun walletConnectSessionsUseCase(): WalletConnectSessionsUseCase val assetsSourceRegistry: AssetSourceRegistry diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/WalletInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/WalletInteractor.kt index 3cf88388af..a4f6aa08c6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/WalletInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/WalletInteractor.kt @@ -3,8 +3,10 @@ package io.novafoundation.nova.feature_assets.domain import io.novafoundation.nova.common.data.model.DataPage import io.novafoundation.nova.common.data.model.PageOffset import io.novafoundation.nova.feature_account_api.domain.model.MetaAccount -import io.novafoundation.nova.feature_assets.domain.common.AssetGroup +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_nft_api.data.repository.NftSyncTrigger import io.novafoundation.nova.feature_wallet_api.domain.interfaces.TransactionFilter @@ -57,8 +59,13 @@ interface WalletInteractor { filters: Set ): Result> - suspend fun groupAssets( + suspend fun groupAssetsByNetwork( assets: List, externalBalances: List - ): Map> + ): Map> + + suspend fun groupAssetsByToken( + assets: List, + externalBalances: List + ): Map> } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/WalletInteractorImpl.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/WalletInteractorImpl.kt index 2113a506ce..58c03b6064 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/WalletInteractorImpl.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/WalletInteractorImpl.kt @@ -8,9 +8,12 @@ import io.novafoundation.nova.feature_account_api.domain.model.MetaAccount import io.novafoundation.nova.feature_account_api.domain.model.requireAccountIdIn import io.novafoundation.nova.feature_assets.data.repository.TransactionHistoryRepository import io.novafoundation.nova.feature_assets.data.repository.assetFilters.AssetFiltersRepository -import io.novafoundation.nova.feature_assets.domain.common.AssetGroup +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByNetwork +import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByToken import io.novafoundation.nova.feature_currency_api.domain.interfaces.CurrencyRepository import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_nft_api.data.repository.NftRepository @@ -168,12 +171,21 @@ class WalletInteractorImpl( } } - override suspend fun groupAssets( + override suspend fun groupAssetsByNetwork( assets: List, externalBalances: List - ): Map> { + ): Map> { val chains = chainRegistry.enabledChainByIdFlow().first() return groupAndSortAssetsByNetwork(assets, externalBalances.aggregatedBalanceByAsset(), chains) } + + override suspend fun groupAssetsByToken( + assets: List, + externalBalances: List + ): Map> { + val chains = chainRegistry.enabledChainByIdFlow().first() + + return groupAndSortAssetsByToken(assets, externalBalances.aggregatedBalanceByAsset(), chains) + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt index f48ca7d1fb..13388f4e1a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt @@ -1,5 +1,7 @@ package io.novafoundation.nova.feature_assets.domain.assets.list +import io.novafoundation.nova.common.data.model.AssetViewMode +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_nft_api.data.model.Nft @@ -15,9 +17,16 @@ private const val BANNER_TAG = "CROWDLOAN_UNLOCK_BANNER" class AssetsListInteractor( private val accountRepository: AccountRepository, private val nftRepository: NftRepository, - private val bannerVisibilityRepository: BannerVisibilityRepository + private val bannerVisibilityRepository: BannerVisibilityRepository, + private val assetsViewModeRepository: AssetsViewModeRepository ) { + fun assetsViewModeFlow() = assetsViewModeRepository.assetsViewModeFlow() + + suspend fun setAssetViewMode(assetViewModel: AssetViewMode) { + assetsViewModeRepository.setAssetsViewMode(assetViewModel) + } + suspend fun fullSyncNft(nft: Nft) = nftRepository.fullNftSync(nft) fun observeNftPreviews(): Flow { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt index 1817c6eecd..e46ffce1a8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt @@ -2,7 +2,7 @@ package io.novafoundation.nova.feature_assets.domain.assets.search import io.novafoundation.nova.common.utils.flowOfAll import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository -import io.novafoundation.nova.feature_assets.domain.common.AssetGroup +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_assets.domain.common.getAssetBaseComparator import io.novafoundation.nova.feature_assets.domain.common.getAssetGroupBaseComparator @@ -41,7 +41,7 @@ class AssetSearchInteractor( fun buyAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow>> { + ): Flow>> { return searchAssetsInternalFlow(queryFlow, externalBalancesFlow) { it.token.configuration.buyProviders.isNotEmpty() } @@ -50,7 +50,7 @@ class AssetSearchInteractor( fun sendAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow>> { + ): Flow>> { val groupComparator = getAssetGroupBaseComparator { it.groupTransferableBalanceFiat } val assetsComparator = getAssetBaseComparator { it.balanceWithOffchain.transferable.fiat } @@ -64,7 +64,7 @@ class AssetSearchInteractor( queryFlow: Flow, externalBalancesFlow: Flow>, coroutineScope: CoroutineScope - ): Flow>> { + ): Flow>> { val filterFlow = getAvailableSwapAssets(forAsset, coroutineScope).map { availableAssetsForSwap -> val filter: AssetSearchFilter = { asset -> val chainAsset = asset.token.configuration @@ -81,7 +81,7 @@ class AssetSearchInteractor( fun searchAssetsFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow>> { + ): Flow>> { return searchAssetsInternalFlow(queryFlow, externalBalancesFlow, filter = null) } @@ -100,10 +100,10 @@ class AssetSearchInteractor( private fun searchAssetsInternalFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - assetGroupComparator: Comparator = getAssetGroupBaseComparator(), + assetGroupComparator: Comparator = getAssetGroupBaseComparator(), assetsComparator: Comparator = getAssetBaseComparator(), filter: AssetSearchFilter?, - ): Flow>> { + ): Flow>> { val filterFlow = flowOf(filter) return searchAssetsInternalFlow(queryFlow, externalBalancesFlow, assetGroupComparator, assetsComparator, filterFlow) @@ -112,10 +112,10 @@ class AssetSearchInteractor( private fun searchAssetsInternalFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - assetGroupComparator: Comparator = getAssetGroupBaseComparator(), + assetGroupComparator: Comparator = getAssetGroupBaseComparator(), assetsComparator: Comparator = getAssetBaseComparator(), filterFlow: Flow, - ): Flow>> { + ): Flow>> { var assetsFlow = accountRepository.selectedMetaAccountFlow() .flatMapLatest { walletRepository.syncedAssetsFlow(it.id) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetPrefixNormalizing.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetPrefixNormalizing.kt new file mode 100644 index 0000000000..bd231e38c4 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetPrefixNormalizing.kt @@ -0,0 +1,26 @@ +package io.novafoundation.nova.feature_assets.domain.common + +import io.novafoundation.nova.common.utils.TokenSymbol +import io.novafoundation.nova.common.utils.asTokenSymbol + +/** + * Some of tokens may have a prefix but may still be original token (like xcDOT, xcHDX) + * For some cases we need to normalize token symbol to original format + */ + +private val normalizingPrefixList: List + get() = listOf("xc") + +fun normalizeTokenSymbol(tokenSymbol: TokenSymbol): TokenSymbol { + return normalizeTokenSymbol(tokenSymbol.value).asTokenSymbol() +} + +fun normalizeTokenSymbol(symbol: String): String { + normalizingPrefixList.forEach { prefix -> + if (symbol.startsWith(prefix)) { + return symbol.removePrefix(prefix) + } + } + + return symbol +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetSorting.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/NetworkAssetSorting.kt similarity index 80% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetSorting.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/NetworkAssetSorting.kt index 58458688e2..8edfb2b18c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetSorting.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/NetworkAssetSorting.kt @@ -12,7 +12,7 @@ import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId import java.math.BigDecimal -class AssetGroup( +class NetworkAssetGroup( val chain: Chain, val groupTotalBalanceFiat: BigDecimal, val groupTransferableBalanceFiat: BigDecimal, @@ -21,34 +21,23 @@ class AssetGroup( class AssetWithOffChainBalance( val asset: Asset, - val balanceWithOffchain: Balance, -) { - - class Balance( - val total: Amount, - val transferable: Amount - ) -} - -class Amount( - val amount: BigDecimal, - val fiat: BigDecimal + val balanceWithOffchain: TotalAndTransferableBalance, ) fun groupAndSortAssetsByNetwork( assets: List, externalBalances: Map, chainsById: Map, - assetGroupComparator: Comparator = getAssetGroupBaseComparator(), + assetGroupComparator: Comparator = getAssetGroupBaseComparator(), assetComparator: Comparator = getAssetBaseComparator() -): Map> { +): Map> { return assets .map { asset -> AssetWithOffChainBalance(asset, asset.totalWithOffChain(externalBalances)) } .filter { chainsById.containsKey(it.asset.token.configuration.chainId) } .groupBy { chainsById.getValue(it.asset.token.configuration.chainId) } .mapValues { (_, assets) -> assets.sortedWith(assetComparator) } .mapKeys { (chain, assets) -> - AssetGroup( + NetworkAssetGroup( chain = chain, groupTotalBalanceFiat = assets.sumByBigDecimal { it.balanceWithOffchain.total.fiat }, groupTransferableBalanceFiat = assets.sumByBigDecimal { it.balanceWithOffchain.transferable.fiat }, @@ -67,14 +56,14 @@ fun getAssetBaseComparator( } fun getAssetGroupBaseComparator( - comparing: (AssetGroup) -> Comparable<*> = AssetGroup::groupTotalBalanceFiat -): Comparator { + comparing: (NetworkAssetGroup) -> Comparable<*> = NetworkAssetGroup::groupTotalBalanceFiat +): Comparator { return compareByDescending(comparing) .thenByDescending { it.zeroBalance } // non-zero balances first - .then(Chain.defaultComparatorFrom(AssetGroup::chain)) + .then(Chain.defaultComparatorFrom(NetworkAssetGroup::chain)) } -private fun Asset.totalWithOffChain(externalBalances: Map): AssetWithOffChainBalance.Balance { +fun Asset.totalWithOffChain(externalBalances: Map): TotalAndTransferableBalance { val onChainTotal = total val offChainTotal = externalBalances[token.configuration.fullId] ?.let(token::amountFromPlanks) @@ -83,7 +72,7 @@ private fun Asset.totalWithOffChain(externalBalances: Map, + externalBalances: Map, + chainsById: Map, + assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), + assetComparator: Comparator = getTokenAssetBaseComparator() +): Map> { + return assets + .filter { chainsById.containsKey(it.token.configuration.chainId) } + .map { asset -> AssetWithNetwork(chainsById.getValue(asset.token.configuration.chainId), asset, asset.totalWithOffChain(externalBalances)) } + .groupBy { mapToTokenGroup(it) } + .mapValues { (_, assets) -> assets.sortedWith(assetComparator) } + .mapKeys { (token, assets) -> + TokenAssetGroup( + token = token, + groupBalance = assets.fold(TotalAndTransferableBalance.ZERO) { acc, element -> acc + element.balanceWithOffChain }, + ) + }.toSortedMap(assetGroupComparator) +} + +fun getTokenAssetBaseComparator( + comparing: (AssetWithNetwork) -> Comparable<*> = { it.balanceWithOffChain.total.amount } +): Comparator { + return compareByDescending(comparing) + .thenByDescending { it.asset.token.configuration.isUtilityAsset } // utility assets first + .thenBy { it.asset.token.configuration.symbol.value } +} + +fun getTokenAssetGroupBaseComparator( + comparing: (TokenAssetGroup) -> Comparable<*> = { it.groupBalance.total.fiat } +): Comparator { + return compareByDescending(comparing) + .thenByDescending { it.groupBalance.total.amount > BigDecimal.ZERO } // non-zero balances first + .then(TokenSymbol.defaultComparatorFrom { it.token.symbol }) +} + +private fun mapToTokenGroup(it: AssetWithNetwork) = TokenAssetGroup.Token( + it.asset.token.configuration.iconUrl, + normalizeTokenSymbol(it.asset.token.configuration.symbol), + it.asset.token.currency, + it.asset.token.coinRate +) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TotalAndTransferableBalance.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TotalAndTransferableBalance.kt new file mode 100644 index 0000000000..4d5b21e3e9 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TotalAndTransferableBalance.kt @@ -0,0 +1,33 @@ +package io.novafoundation.nova.feature_assets.domain.common + +import java.math.BigDecimal + +class TotalAndTransferableBalance( + val total: Amount, + val transferable: Amount +) { + + companion object { + val ZERO = TotalAndTransferableBalance(Amount(BigDecimal.ZERO, BigDecimal.ZERO), Amount(BigDecimal.ZERO, BigDecimal.ZERO)) + } + + operator fun plus(other: TotalAndTransferableBalance): TotalAndTransferableBalance { + return TotalAndTransferableBalance( + total + other.total, + transferable + other.transferable + ) + } +} + +class Amount( + val amount: BigDecimal, + val fiat: BigDecimal +) { + + operator fun plus(other: Amount): Amount { + return Amount( + amount + other.amount, + fiat + other.fiat + ) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetGroupingDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetGroupingDecoration.kt index 911c5b5680..895a34efdb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetGroupingDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetGroupingDecoration.kt @@ -8,11 +8,14 @@ import android.view.View import androidx.core.view.children import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import io.novafoundation.nova.common.list.GroupedListAdapter import io.novafoundation.nova.common.utils.dp import io.novafoundation.nova.common.view.shape.addRipple import io.novafoundation.nova.common.view.shape.getRoundedCornerDrawable import io.novafoundation.nova.feature_assets.R +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetGroupViewHolder +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetViewHolder +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetGroupViewHolder +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetViewHolder import kotlin.math.roundToInt /** @@ -47,7 +50,6 @@ class AssetGroupingDecoration( val bindingPosition = viewHolder.bindingAdapterPosition - val currentType = assetsAdapter.getItemViewType(bindingPosition) val nextType = assetsAdapter.getItemViewTypeOrNull(bindingPosition + 1) if (groupTop == null) { @@ -57,7 +59,7 @@ class AssetGroupingDecoration( when { // if group is finished - isFinalItemInGroup(currentType, nextType) -> { + isFinalItemInGroup(nextType) -> { parent.getDecoratedBoundsWithMargins(view, bounds) bounds.set(view.left, bounds.top, view.right, bounds.bottom) @@ -97,10 +99,9 @@ class AssetGroupingDecoration( val adapterPosition = viewHolder.bindingAdapterPosition - val currentType = assetsAdapter.getItemViewTypeOrNull(adapterPosition) val nextType = assetsAdapter.getItemViewTypeOrNull(adapterPosition + 1) - val bottom = if (isFinalItemInGroup(currentType, nextType)) groupInnerSpacing + groupOuterSpacing else 0 + val bottom = if (isFinalItemInGroup(nextType)) groupInnerSpacing + groupOuterSpacing else 0 outRect.set(0, 0, 0, bottom) } @@ -111,13 +112,17 @@ class AssetGroupingDecoration( return getItemViewType(position) } - private fun isFinalItemInGroup(currentType: Int?, nextType: Int?): Boolean { - return currentType == GroupedListAdapter.TYPE_CHILD && (nextType == GroupedListAdapter.TYPE_GROUP || nextType == null) + private fun isFinalItemInGroup(nextType: Int?): Boolean { + return nextType == TYPE_NETWORK_GROUP || nextType == TYPE_TOKEN_GROUP || nextType == null } private fun shouldSkip(viewHolder: RecyclerView.ViewHolder): Boolean { - return viewHolder.bindingAdapterPosition == RecyclerView.NO_POSITION || - (viewHolder !is AssetViewHolder && viewHolder !is AssetGroupViewHolder) + val isGroupViewHolder = viewHolder is NetworkAssetViewHolder || + viewHolder is NetworkAssetGroupViewHolder || + viewHolder is TokenAssetViewHolder || + viewHolder is TokenAssetGroupViewHolder + + return viewHolder.bindingAdapterPosition == RecyclerView.NO_POSITION || !isGroupViewHolder } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt new file mode 100644 index 0000000000..84e7d724bf --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -0,0 +1,105 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common + +import io.novafoundation.nova.common.data.model.AssetViewMode +import io.novafoundation.nova.common.data.model.switch +import io.novafoundation.nova.common.utils.toggle +import io.novafoundation.nova.common.utils.updateValue +import io.novafoundation.nova.feature_assets.domain.WalletInteractor +import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.assets.list.AssetsListInteractor +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi +import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor +import io.novafoundation.nova.feature_wallet_api.domain.model.Asset +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.first + +class AssetListMixinFactory( + private val walletInteractor: WalletInteractor, + private val assetsListInteractor: AssetsListInteractor, + private val currencyInteractor: CurrencyInteractor, + private val externalBalancesInteractor: ExternalBalancesInteractor +) { + + fun create(): AssetListMixin = RealAssetListMixin( + walletInteractor, + assetsListInteractor, + currencyInteractor, + externalBalancesInteractor + ) +} + +interface AssetListMixin { + + val assetsFlow: Flow> + + val filteredAssetsFlow: Flow> + + val assetModelsFlow: Flow> + + fun expandToken(tokenGroupUi: TokenGroupUi) + suspend fun switchViewMode() + val assetsViewModeFlow: Flow +} + +class RealAssetListMixin( + private val walletInteractor: WalletInteractor, + private val assetsListInteractor: AssetsListInteractor, + private val currencyInteractor: CurrencyInteractor, + private val externalBalancesInteractor: ExternalBalancesInteractor +) : AssetListMixin { + + override val assetsFlow = walletInteractor.assetsFlow() + + override val filteredAssetsFlow = walletInteractor.filterAssets(assetsFlow) + + private val selectedCurrency = currencyInteractor.observeSelectCurrency() + + private val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() + + private val expandedTokenIdsFlow = MutableStateFlow(setOf()) + + override val assetsViewModeFlow = assetsListInteractor.assetsViewModeFlow() + + override val assetModelsFlow = combine( + filteredAssetsFlow, + selectedCurrency, + externalBalancesFlow, + assetsViewModeFlow, + expandedTokenIdsFlow + ) { assets, currency, externalBalances, viewMode, expandedTokens -> + when (viewMode) { + AssetViewMode.NETWORKS -> walletInteractor.groupAssetsByNetwork(assets, externalBalances).mapGroupedAssetsToUi(currency) + AssetViewMode.TOKENS -> walletInteractor.groupAssetsByToken(assets, externalBalances) + .mapValues { filterExpandedItems(it, expandedTokens) } + .mapGroupedAssetsToUi() + } + }.distinctUntilChanged() + + override suspend fun switchViewMode() { + val assetViewMode = assetsViewModeFlow.first() + + assetsListInteractor.setAssetViewMode(assetViewMode.switch()) + } + + override fun expandToken(tokenGroupUi: TokenGroupUi) { + expandedTokenIdsFlow.updateValue { it.toggle(tokenGroupUi.id) } + } + + private fun filterExpandedItems(entry: Map.Entry>, expandedTokens: Set): List { + val group = entry.key + val items = entry.value + + if (group.token.symbol.value in expandedTokens) { + return items + } + + return emptyList() + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt index 636dd1e8d0..b3543cf310 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt @@ -1,146 +1,116 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common -import android.view.View +import android.annotation.SuppressLint import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView.ViewHolder import coil.ImageLoader -import io.novafoundation.nova.common.list.BaseGroupedDiffCallback -import io.novafoundation.nova.common.list.GroupedListAdapter -import io.novafoundation.nova.common.list.GroupedListHolder import io.novafoundation.nova.common.list.PayloadGenerator import io.novafoundation.nova.common.list.resolvePayload import io.novafoundation.nova.common.utils.inflateChild -import io.novafoundation.nova.common.utils.setTextColorRes -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.R -import io.novafoundation.nova.feature_assets.presentation.balance.list.model.AssetGroupUi +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetGroupViewHolder +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetViewHolder +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetGroupViewHolder +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetViewHolder +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkAssetUi +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkGroupUi +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel -import kotlinx.android.synthetic.main.item_asset.view.itemAssetBalance -import kotlinx.android.synthetic.main.item_asset.view.itemAssetImage -import kotlinx.android.synthetic.main.item_asset.view.itemAssetPriceAmount -import kotlinx.android.synthetic.main.item_asset.view.itemAssetRate -import kotlinx.android.synthetic.main.item_asset.view.itemAssetRateChange -import kotlinx.android.synthetic.main.item_asset.view.itemAssetToken -import kotlinx.android.synthetic.main.item_asset_group.view.itemAssetGroupBalance -import kotlinx.android.synthetic.main.item_asset_group.view.itemAssetGroupChain - -val priceRateExtractor = { assetModel: AssetModel -> assetModel.token.rate } -val recentChangeExtractor = { assetModel: AssetModel -> assetModel.token.recentRateChange } + +private val priceRateExtractor = { assetModel: NetworkAssetUi -> assetModel.asset.token.rate } +private val recentChangeExtractor = { assetModel: NetworkAssetUi -> assetModel.asset.token.recentRateChange } +private val amountExtractor = { assetModel: NetworkAssetUi -> assetModel.asset.amount } + +const val TYPE_NETWORK_GROUP = 0 +const val TYPE_NETWORK_ASSET = 1 +const val TYPE_TOKEN_GROUP = 2 +const val TYPE_TOKEN_ASSET = 3 class BalanceListAdapter( private val imageLoader: ImageLoader, private val itemHandler: ItemAssetHandler, -) : GroupedListAdapter(DiffCallback) { +) : ListAdapter(DiffCallback) { interface ItemAssetHandler { fun assetClicked(asset: AssetModel) - } - - override fun createGroupViewHolder(parent: ViewGroup): GroupedListHolder { - val view = parent.inflateChild(R.layout.item_asset_group) - - return AssetGroupViewHolder(view) - } - - override fun createChildViewHolder(parent: ViewGroup): GroupedListHolder { - val view = parent.inflateChild(R.layout.item_asset) - - return AssetViewHolder(view, imageLoader) - } - - override fun bindGroup(holder: GroupedListHolder, group: AssetGroupUi) { - require(holder is AssetGroupViewHolder) - holder.bind(group) + fun tokenGroupClicked(tokenGroup: TokenGroupUi) } - override fun bindChild(holder: GroupedListHolder, position: Int, child: AssetModel, payloads: List) { - require(holder is AssetViewHolder) - - resolvePayload(holder, position, payloads) { - when (it) { - priceRateExtractor -> holder.bindPriceInfo(child) - recentChangeExtractor -> holder.bindRecentChange(child) - AssetModel::amount -> holder.bindTotal(child) - } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return when (viewType) { + TYPE_NETWORK_GROUP -> NetworkAssetGroupViewHolder(parent.inflateChild(R.layout.item_network_asset_group)) + TYPE_NETWORK_ASSET -> NetworkAssetViewHolder(parent.inflateChild(R.layout.item_network_asset), imageLoader) + TYPE_TOKEN_GROUP -> TokenAssetGroupViewHolder(parent.inflateChild(R.layout.item_token_asset_group), imageLoader) + TYPE_TOKEN_ASSET -> TokenAssetViewHolder(parent.inflateChild(R.layout.item_token_asset), imageLoader) + else -> error("Unknown view type") } } - override fun bindChild(holder: GroupedListHolder, child: AssetModel) { - require(holder is AssetViewHolder) - - holder.bind(child, itemHandler) - } -} - -class AssetGroupViewHolder( - containerView: View, -) : GroupedListHolder(containerView) { - - fun bind(assetGroup: AssetGroupUi) = with(containerView) { - itemAssetGroupChain.setChain(assetGroup.chainUi) - itemAssetGroupBalance.text = assetGroup.groupBalanceFiat - } -} - -class AssetViewHolder( - containerView: View, - private val imageLoader: ImageLoader, -) : GroupedListHolder(containerView) { - - fun bind(asset: AssetModel, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { - itemAssetImage.loadTokenIcon(asset.token.configuration.iconUrl, imageLoader) - - bindPriceInfo(asset) - - bindRecentChange(asset) - - bindTotal(asset) - - itemAssetToken.text = asset.token.configuration.symbol.value - - setOnClickListener { itemHandler.assetClicked(asset) } + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + return when (holder) { + is NetworkAssetGroupViewHolder -> holder.bind(getItem(position) as NetworkGroupUi) + is NetworkAssetViewHolder -> holder.bind(getItem(position) as NetworkAssetUi, itemHandler) + is TokenAssetGroupViewHolder -> holder.bind(getItem(position) as TokenGroupUi, itemHandler) + is TokenAssetViewHolder -> holder.bind(getItem(position) as TokenAssetUi, itemHandler) + else -> error("Unknown holder") + } } - fun bindTotal(asset: AssetModel) { - containerView.itemAssetBalance.text = asset.amount.token - containerView.itemAssetPriceAmount.text = asset.amount.fiat - } + override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList) { + when (holder) { + is NetworkAssetViewHolder -> { + val item = getItem(position) as NetworkAssetUi + resolvePayload(holder, position, payloads) { + when (it) { + priceRateExtractor -> holder.bindPriceInfo(item) + recentChangeExtractor -> holder.bindRecentChange(item) + AssetModel::amount -> holder.bindTotal(item) + } + } + } - fun bindRecentChange(asset: AssetModel) = with(containerView) { - itemAssetRateChange.setTextColorRes(asset.token.rateChangeColorRes) - itemAssetRateChange.text = asset.token.recentRateChange + else -> super.onBindViewHolder(holder, position, payloads) + } } - fun bindPriceInfo(asset: AssetModel) = with(containerView) { - itemAssetRate.text = asset.token.rate + override fun getItemViewType(position: Int): Int { + return when (getItem(position)) { + is NetworkGroupUi -> TYPE_NETWORK_GROUP + is NetworkAssetUi -> TYPE_NETWORK_ASSET + is TokenGroupUi -> TYPE_TOKEN_GROUP + is TokenAssetUi -> TYPE_TOKEN_ASSET + else -> error("Unknown item type") + } } } -private object DiffCallback : BaseGroupedDiffCallback(AssetGroupUi::class.java) { +private object DiffCallback : DiffUtil.ItemCallback() { - override fun areGroupItemsTheSame(oldItem: AssetGroupUi, newItem: AssetGroupUi): Boolean { - return oldItem.chainUi.id == newItem.chainUi.id + override fun areItemsTheSame(oldItem: BalanceListRvItem, newItem: BalanceListRvItem): Boolean { + return oldItem.id == newItem.id } - override fun areGroupContentsTheSame(oldItem: AssetGroupUi, newItem: AssetGroupUi): Boolean { + @SuppressLint("DiffUtilEquals") + override fun areContentsTheSame(oldItem: BalanceListRvItem, newItem: BalanceListRvItem): Boolean { return oldItem == newItem } - override fun areChildItemsTheSame(oldItem: AssetModel, newItem: AssetModel): Boolean { - return oldItem.token.configuration == newItem.token.configuration - } - - override fun areChildContentsTheSame(oldItem: AssetModel, newItem: AssetModel): Boolean { - return oldItem == newItem - } + override fun getChangePayload(oldItem: BalanceListRvItem, newItem: BalanceListRvItem): Any? { + if (oldItem is NetworkAssetUi && newItem is NetworkAssetUi) { + return AssetPayloadGenerator.diff(oldItem, newItem) + } - override fun getChildChangePayload(oldItem: AssetModel, newItem: AssetModel): Any? { - return AssetPayloadGenerator.diff(oldItem, newItem) + return null } } -private object AssetPayloadGenerator : PayloadGenerator( +private object AssetPayloadGenerator : PayloadGenerator( priceRateExtractor, recentChangeExtractor, - AssetModel::amount + amountExtractor ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt new file mode 100644 index 0000000000..352490f828 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt @@ -0,0 +1,17 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common.holders + +import android.view.View +import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkGroupUi +import kotlinx.android.synthetic.main.item_network_asset_group.view.itemAssetGroupBalance +import kotlinx.android.synthetic.main.item_network_asset_group.view.itemAssetGroupChain + +class NetworkAssetGroupViewHolder( + containerView: View, +) : GroupedListHolder(containerView) { + + fun bind(assetGroup: NetworkGroupUi) = with(containerView) { + itemAssetGroupChain.setChain(assetGroup.chainUi) + itemAssetGroupBalance.text = assetGroup.groupBalanceFiat + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt new file mode 100644 index 0000000000..a0fb56fe45 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt @@ -0,0 +1,53 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common.holders + +import android.view.View +import coil.ImageLoader +import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.common.utils.setTextColorRes +import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon +import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkAssetUi +import kotlinx.android.synthetic.main.item_network_asset.view.itemAssetBalance +import kotlinx.android.synthetic.main.item_network_asset.view.itemAssetImage +import kotlinx.android.synthetic.main.item_network_asset.view.itemAssetPriceAmount +import kotlinx.android.synthetic.main.item_network_asset.view.itemAssetRate +import kotlinx.android.synthetic.main.item_network_asset.view.itemAssetRateChange +import kotlinx.android.synthetic.main.item_network_asset.view.itemAssetToken + +class NetworkAssetViewHolder( + containerView: View, + private val imageLoader: ImageLoader, +) : GroupedListHolder(containerView) { + + fun bind(networkAsset: NetworkAssetUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { + val asset = networkAsset.asset + itemAssetImage.loadTokenIcon(asset.token.configuration.iconUrl, imageLoader) + + bindPriceInfo(networkAsset) + + bindRecentChange(networkAsset) + + bindTotal(networkAsset) + + itemAssetToken.text = asset.token.configuration.symbol.value + + setOnClickListener { itemHandler.assetClicked(asset) } + } + + fun bindTotal(networkAsset: NetworkAssetUi) { + val asset = networkAsset.asset + containerView.itemAssetBalance.text = asset.amount.token + containerView.itemAssetPriceAmount.text = asset.amount.fiat + } + + fun bindRecentChange(networkAsset: NetworkAssetUi) = with(containerView) { + val asset = networkAsset.asset + itemAssetRateChange.setTextColorRes(asset.token.rateChangeColorRes) + itemAssetRateChange.text = asset.token.recentRateChange + } + + fun bindPriceInfo(networkAsset: NetworkAssetUi) = with(containerView) { + val asset = networkAsset.asset + itemAssetRate.text = asset.token.rate + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt new file mode 100644 index 0000000000..6915ab54dd --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt @@ -0,0 +1,50 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common.holders + +import android.view.View +import coil.ImageLoader +import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.common.utils.setTextColorRes +import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon +import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi +import kotlinx.android.synthetic.main.item_token_asset_group.view.itemAssetTokenGroupBalance +import kotlinx.android.synthetic.main.item_token_asset_group.view.itemAssetTokenGroupPriceAmount +import kotlinx.android.synthetic.main.item_token_asset_group.view.itemAssetTokenGroupRate +import kotlinx.android.synthetic.main.item_token_asset_group.view.itemAssetTokenGroupRateChange +import kotlinx.android.synthetic.main.item_token_asset_group.view.itemAssetTokenGroupToken +import kotlinx.android.synthetic.main.item_token_asset_group.view.itemTokenGroupAssetImage + +class TokenAssetGroupViewHolder( + containerView: View, + private val imageLoader: ImageLoader, +) : GroupedListHolder(containerView) { + + fun bind(tokenGroup: TokenGroupUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { + itemTokenGroupAssetImage.loadTokenIcon(tokenGroup.tokenIcon, imageLoader) + + bindPriceInfo(tokenGroup) + + bindRecentChange(tokenGroup) + + bindTotal(tokenGroup) + + itemAssetTokenGroupToken.text = tokenGroup.tokenSymbol + + setOnClickListener { itemHandler.tokenGroupClicked(tokenGroup) } + } + + fun bindTotal(networkAsset: TokenGroupUi) { + val balance = networkAsset.balance + containerView.itemAssetTokenGroupBalance.text = balance.token + containerView.itemAssetTokenGroupPriceAmount.text = balance.fiat + } + + fun bindRecentChange(networkAsset: TokenGroupUi) = with(containerView) { + itemAssetTokenGroupRateChange.setTextColorRes(networkAsset.rateChangeColorRes) + itemAssetTokenGroupRateChange.text = networkAsset.recentRateChange + } + + fun bindPriceInfo(networkAsset: TokenGroupUi) = with(containerView) { + itemAssetTokenGroupRate.text = networkAsset.rate + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt new file mode 100644 index 0000000000..667a59da57 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt @@ -0,0 +1,39 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common.holders + +import android.view.View +import coil.ImageLoader +import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon +import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi +import kotlinx.android.synthetic.main.item_token_asset.view.itemTokenAssetImage +import kotlinx.android.synthetic.main.item_token_asset.view.itemTokenAssetToken +import kotlinx.android.synthetic.main.item_token_asset.view.itemTokenAssetBalance +import kotlinx.android.synthetic.main.item_token_asset.view.itemTokenAssetChainIcon +import kotlinx.android.synthetic.main.item_token_asset.view.itemTokenAssetChainName +import kotlinx.android.synthetic.main.item_token_asset.view.itemTokenAssetPriceAmount + +class TokenAssetViewHolder( + containerView: View, + private val imageLoader: ImageLoader, +) : GroupedListHolder(containerView) { + + fun bind(tokenAsset: TokenAssetUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { + val asset = tokenAsset.asset + itemTokenAssetImage.loadTokenIcon(asset.token.configuration.iconUrl, imageLoader) + itemTokenAssetChainIcon.loadTokenIcon(tokenAsset.chain.icon, imageLoader) + itemTokenAssetChainName.text = tokenAsset.chain.name + + bindTotal(tokenAsset) + + itemTokenAssetToken.text = asset.token.configuration.symbol.value + + setOnClickListener { itemHandler.assetClicked(asset) } + } + + fun bindTotal(networkAsset: TokenAssetUi) { + val asset = networkAsset.asset + containerView.itemTokenAssetBalance.text = asset.amount.token + containerView.itemTokenAssetPriceAmount.text = asset.amount.fiat + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt new file mode 100644 index 0000000000..ef514c3235 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt @@ -0,0 +1,29 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common.mappers + +import io.novafoundation.nova.common.utils.orZero +import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.presentation.model.AssetModel +import io.novafoundation.nova.feature_currency_api.domain.model.Currency +import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency +import io.novafoundation.nova.feature_wallet_api.domain.model.Asset +import io.novafoundation.nova.feature_wallet_api.domain.model.CoinRateChange +import io.novafoundation.nova.feature_wallet_api.presentation.model.mapAmountToAmountModel + +fun mapCoinRateChange(coinRateChange: CoinRateChange?, currency: Currency): String { + val rateChange = coinRateChange?.rate + return rateChange.orZero().formatAsCurrency(currency) +} + +fun mapAssetToAssetModel( + asset: Asset, + balance: Amount +): AssetModel { + return AssetModel( + token = mapTokenToTokenModel(asset.token), + amount = mapAmountToAmountModel( + amount = balance.amount, + asset = asset, + includeAssetTicker = false + ) + ) +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt similarity index 50% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetMappers.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt index 6799b92fd1..e3a2e5327a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt @@ -1,84 +1,74 @@ -package io.novafoundation.nova.feature_assets.presentation.balance.common +package io.novafoundation.nova.feature_assets.presentation.balance.common.mappers +import androidx.annotation.ColorRes import io.novafoundation.nova.common.list.GroupedList import io.novafoundation.nova.common.list.toListWithHeaders import io.novafoundation.nova.common.utils.formatting.formatAsChange import io.novafoundation.nova.common.utils.isNonNegative import io.novafoundation.nova.common.utils.isZero -import io.novafoundation.nova.common.utils.orZero import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.common.Amount -import io.novafoundation.nova.feature_assets.domain.common.AssetGroup +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance -import io.novafoundation.nova.feature_assets.presentation.balance.list.model.AssetGroupUi -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel +import io.novafoundation.nova.feature_assets.domain.common.TotalAndTransferableBalance +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkAssetUi +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkGroupUi import io.novafoundation.nova.feature_assets.presentation.model.TokenModel import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency +import io.novafoundation.nova.feature_wallet_api.domain.model.CoinRateChange import io.novafoundation.nova.feature_wallet_api.domain.model.Token -import io.novafoundation.nova.feature_wallet_api.presentation.model.mapAmountToAmountModel import java.math.BigDecimal -fun GroupedList.mapGroupedAssetsToUi( +fun GroupedList.mapGroupedAssetsToUi( currency: Currency, - groupBalance: (AssetGroup) -> BigDecimal = AssetGroup::groupTotalBalanceFiat, - balance: (AssetWithOffChainBalance.Balance) -> Amount = AssetWithOffChainBalance.Balance::total, -): List { + groupBalance: (NetworkAssetGroup) -> BigDecimal = NetworkAssetGroup::groupTotalBalanceFiat, + balance: (TotalAndTransferableBalance) -> Amount = TotalAndTransferableBalance::total, +): List { return mapKeys { (assetGroup, _) -> mapAssetGroupToUi(assetGroup, currency, groupBalance) } .mapValues { (_, assets) -> mapAssetsToAssetModels(assets, balance) } .toListWithHeaders() + .filterIsInstance() } fun mapTokenToTokenModel(token: Token): TokenModel { return with(token) { - val rateChange = token.coinRate?.recentRateChange - - val changeColorRes = when { - rateChange == null || rateChange.isZero -> R.color.text_secondary - rateChange.isNonNegative -> R.color.text_positive - else -> R.color.text_negative - } - TokenModel( configuration = configuration, - rate = coinRate?.rate.orZero().formatAsCurrency(token.currency), + rate = mapCoinRateChange(token.coinRate, token.currency), recentRateChange = (coinRate?.recentRateChange ?: BigDecimal.ZERO).formatAsChange(), - rateChangeColorRes = changeColorRes + rateChangeColorRes = mapCoinRateChangeColorRes(coinRate) ) } } +@ColorRes +fun mapCoinRateChangeColorRes(coinRateChange: CoinRateChange?): Int { + val rateChange = coinRateChange?.recentRateChange + + return when { + rateChange == null || rateChange.isZero -> R.color.text_secondary + rateChange.isNonNegative -> R.color.text_positive + else -> R.color.text_negative + } +} + private fun mapAssetsToAssetModels( assets: List, - balance: (AssetWithOffChainBalance.Balance) -> Amount -): List { - return assets.map { mapAssetToAssetModel(it, balance) } + balance: (TotalAndTransferableBalance) -> Amount +): List { + return assets.map { NetworkAssetUi(mapAssetToAssetModel(it.asset, balance(it.balanceWithOffchain))) } } private fun mapAssetGroupToUi( - assetGroup: AssetGroup, + assetGroup: NetworkAssetGroup, currency: Currency, - groupBalance: (AssetGroup) -> BigDecimal -): AssetGroupUi { - return AssetGroupUi( + groupBalance: (NetworkAssetGroup) -> BigDecimal +): BalanceListRvItem { + return NetworkGroupUi( chainUi = mapChainToUi(assetGroup.chain), groupBalanceFiat = groupBalance(assetGroup).formatAsCurrency(currency) ) } - -private fun mapAssetToAssetModel( - assetWithOffChainBalance: AssetWithOffChainBalance, - balance: (AssetWithOffChainBalance.Balance) -> Amount -): AssetModel { - return with(assetWithOffChainBalance) { - AssetModel( - token = mapTokenToTokenModel(asset.token), - amount = mapAmountToAmountModel( - amount = balance(balanceWithOffchain).amount, - asset = asset, - includeAssetTicker = false - ) - ) - } -} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt new file mode 100644 index 0000000000..54d853825f --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -0,0 +1,52 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common.mappers + +import io.novafoundation.nova.common.list.GroupedList +import io.novafoundation.nova.common.list.toListWithHeaders +import io.novafoundation.nova.common.utils.formatTokenAmount +import io.novafoundation.nova.common.utils.formatting.formatAsChange +import io.novafoundation.nova.common.utils.orZero +import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi +import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup +import io.novafoundation.nova.feature_assets.domain.common.TotalAndTransferableBalance +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi +import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel + +fun GroupedList.mapGroupedAssetsToUi( + groupBalance: (TokenAssetGroup) -> Amount = { it.groupBalance.total }, + balance: (TotalAndTransferableBalance) -> Amount = TotalAndTransferableBalance::total, +): List { + return mapKeys { (assetGroup, _) -> mapAssetGroupToUi(assetGroup, groupBalance) } + .mapValues { (_, assets) -> mapAssetsToAssetModels(assets, balance) } + .toListWithHeaders() + .filterIsInstance() +} + +private fun mapAssetsToAssetModels( + assets: List, + balance: (TotalAndTransferableBalance) -> Amount +): List { + return assets.map { TokenAssetUi(mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } +} + +private fun mapAssetGroupToUi( + assetGroup: TokenAssetGroup, + groupBalance: (TokenAssetGroup) -> Amount +): BalanceListRvItem { + val balance = groupBalance(assetGroup) + return TokenGroupUi( + tokenIcon = assetGroup.token.icon, + rate = mapCoinRateChange(assetGroup.token.coinRate, assetGroup.token.currency), + recentRateChange = assetGroup.token.coinRate?.recentRateChange.orZero().formatAsChange(), + rateChangeColorRes = mapCoinRateChangeColorRes(assetGroup.token.coinRate), + tokenSymbol = assetGroup.token.symbol.value, + balance = AmountModel( + token = balance.amount.formatTokenAmount(), + fiat = balance.fiat.formatAsCurrency(assetGroup.token.currency) + ) + ) +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt index 26e0f2bd36..a1f48315d7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt @@ -16,7 +16,7 @@ import io.novafoundation.nova.feature_assets.domain.locks.BalanceLocksInteractor import io.novafoundation.nova.feature_assets.domain.send.SendInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.balance.common.mapTokenToTokenModel +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapTokenToTokenModel import io.novafoundation.nova.feature_assets.presentation.model.BalanceLocksModel import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload import io.novafoundation.nova.feature_assets.presentation.transaction.filter.TransactionHistoryFilterPayload diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index ccd2a52162..6277b1b41f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -17,6 +17,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.Bala import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetGroupingDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.common.applyDefaultTo +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetsHeaderAdapter import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import kotlinx.android.synthetic.main.fragment_balance_list.balanceListAssets @@ -86,7 +87,7 @@ class BalanceListFragment : } override fun subscribe(viewModel: BalanceListViewModel) { - viewModel.assetModelsFlow.observe { + viewModel.assetListMixin.assetModelsFlow.observe { assetsAdapter.submitList(it) { balanceListAssets?.invalidateItemDecorations() } @@ -129,12 +130,18 @@ class BalanceListFragment : viewModel.filtersIndicatorIcon.observe(headerAdapter::setFilterIconRes) viewModel.shouldShowCrowdloanBanner.observe(headerAdapter::setCrowdloanBannerVisible) + + viewModel.assetViewModeModelFlow.observe { headerAdapter.setAssetViewModeModel(it) } } override fun assetClicked(asset: AssetModel) { viewModel.assetClicked(asset) } + override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { + showMessage("Not implemented yet") + } + override fun totalBalanceClicked() { viewModel.balanceBreakdownClicked() } @@ -183,6 +190,10 @@ class BalanceListFragment : viewModel.crowdloanBannerCloseClicked() } + override fun assetViewModeClicked() { + viewModel.switchViewMode() + } + override fun swapClicked() { viewModel.swapClicked() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt index 5fb4dab4b3..a85fb30ace 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt @@ -8,6 +8,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.data.model.AssetViewMode import io.novafoundation.nova.common.presentation.LoadingState import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.Event @@ -28,9 +29,10 @@ import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.mode import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.model.BalanceBreakdownItem import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.model.BalanceBreakdownTotal import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.model.TotalBalanceBreakdownModel -import io.novafoundation.nova.feature_assets.presentation.balance.common.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetListMixinFactory import io.novafoundation.nova.feature_assets.presentation.balance.list.model.NftPreviewUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.TotalBalanceModel +import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetViewModeModel import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency @@ -46,7 +48,6 @@ import io.novafoundation.nova.feature_wallet_connect_api.presentation.mapNumberO import kotlinx.coroutines.async import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.launchIn @@ -71,7 +72,8 @@ class BalanceListViewModel( private val externalBalancesInteractor: ExternalBalancesInteractor, private val resourceManager: ResourceManager, private val walletConnectSessionsUseCase: WalletConnectSessionsUseCase, - private val swapAvailabilityInteractor: SwapAvailabilityInteractor + private val swapAvailabilityInteractor: SwapAvailabilityInteractor, + private val assetListMixinFactory: AssetListMixinFactory ) : BaseViewModel() { private val _hideRefreshEvent = MutableLiveData>() @@ -89,9 +91,9 @@ class BalanceListViewModel( walletInteractor::syncAllNfts ) - private val assetsFlow = walletInteractor.assetsFlow() + private val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() - private val filteredAssetsFlow = walletInteractor.filterAssets(assetsFlow) + val assetListMixin = assetListMixinFactory.create() private val isFiltersEnabledFlow = walletInteractor.isFiltersEnabledFlow() @@ -105,10 +107,7 @@ class BalanceListViewModel( val selectedWalletModelFlow = selectedAccountUseCase.selectedWalletModelFlow() .shareInBackground() - private val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() - .shareInBackground() - - private val balanceBreakdown = balanceBreakdownInteractor.balanceBreakdownFlow(assetsFlow, externalBalancesFlow) + private val balanceBreakdown = balanceBreakdownInteractor.balanceBreakdownFlow(assetListMixin.assetsFlow, externalBalancesFlow) .shareInBackground() private val nftsPreviews = assetsListInteractor.observeNftPreviews() @@ -125,12 +124,6 @@ class BalanceListViewModel( .inBackground() .share() - val assetModelsFlow = combine(filteredAssetsFlow, selectedCurrency, externalBalancesFlow) { assets, currency, externalBalances -> - walletInteractor.groupAssets(assets, externalBalances).mapGroupedAssetsToUi(currency) - } - .distinctUntilChanged() - .shareInBackground() - val totalBalanceFlow = combine( balanceBreakdown, swapAvailabilityInteractor.anySwapAvailableFlow() @@ -146,7 +139,7 @@ class BalanceListViewModel( .inBackground() .share() - val shouldShowPlaceholderFlow = filteredAssetsFlow.map { it.isEmpty() } + val shouldShowPlaceholderFlow = assetListMixin.filteredAssetsFlow.map { it.isEmpty() } val balanceBreakdownFlow = balanceBreakdown.map { val currency = selectedCurrency.first() @@ -171,6 +164,13 @@ class BalanceListViewModel( val shouldShowCrowdloanBanner = assetsListInteractor.shouldShowCrowdloansBanner() .shareInBackground() + val assetViewModeModelFlow = assetListMixin.assetsViewModeFlow.map { + when (it) { + AssetViewMode.NETWORKS -> AssetViewModeModel(R.drawable.ic_asset_view_networks, R.string.asset_view_networks) + AssetViewMode.TOKENS -> AssetViewModeModel(R.drawable.ic_asset_view_tokens, R.string.asset_view_tokens) + } + } + init { selectedCurrency .onEach { fullSync() } @@ -349,4 +349,8 @@ class BalanceListViewModel( private fun hideCrowdloanBanner() = launch { assetsListInteractor.hideCrowdloanBanner() } + + fun switchViewMode() { + launch { assetListMixin.switchViewMode() } + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt index 779ddb96eb..dfdcbc7bc4 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModelProvider import dagger.Module import dagger.Provides import dagger.multibindings.IntoMap +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey @@ -18,6 +19,7 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.assets.list.AssetsListInteractor import io.novafoundation.nova.feature_assets.domain.breakdown.BalanceBreakdownInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetListMixinFactory import io.novafoundation.nova.feature_assets.presentation.balance.list.BalanceListViewModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_nft_api.data.repository.NftRepository @@ -34,8 +36,9 @@ class BalanceListModule { fun provideInteractor( accountRepository: AccountRepository, nftRepository: NftRepository, - bannerVisibilityRepository: BannerVisibilityRepository - ) = AssetsListInteractor(accountRepository, nftRepository, bannerVisibilityRepository) + bannerVisibilityRepository: BannerVisibilityRepository, + assetsViewModeRepository: AssetsViewModeRepository + ) = AssetsListInteractor(accountRepository, nftRepository, bannerVisibilityRepository, assetsViewModeRepository) @Provides @ScreenScope @@ -51,6 +54,22 @@ class BalanceListModule { ) } + @Provides + @ScreenScope + fun provideAssetListMixinFactory( + walletInteractor: WalletInteractor, + assetsListInteractor: AssetsListInteractor, + currencyInteractor: CurrencyInteractor, + externalBalancesInteractor: ExternalBalancesInteractor + ): AssetListMixinFactory { + return AssetListMixinFactory( + walletInteractor, + assetsListInteractor, + currencyInteractor, + externalBalancesInteractor + ) + } + @Provides @IntoMap @ViewModelKey(BalanceListViewModel::class) @@ -64,7 +83,8 @@ class BalanceListModule { externalBalancesInteractor: ExternalBalancesInteractor, resourceManager: ResourceManager, walletConnectSessionsUseCase: WalletConnectSessionsUseCase, - swapAvailabilityInteractor: SwapAvailabilityInteractor + swapAvailabilityInteractor: SwapAvailabilityInteractor, + assetListMixinFactory: AssetListMixinFactory ): ViewModel { return BalanceListViewModel( walletInteractor = walletInteractor, @@ -76,7 +96,8 @@ class BalanceListModule { externalBalancesInteractor = externalBalancesInteractor, resourceManager = resourceManager, walletConnectSessionsUseCase = walletConnectSessionsUseCase, - swapAvailabilityInteractor = swapAvailabilityInteractor + swapAvailabilityInteractor = swapAvailabilityInteractor, + assetListMixinFactory = assetListMixinFactory ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt new file mode 100644 index 0000000000..4926ab6559 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt @@ -0,0 +1,13 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items + +import io.novafoundation.nova.feature_assets.presentation.model.AssetModel + +interface BalanceListRvItem { + val id: String +} + +interface AssetGroupRvItem : BalanceListRvItem + +interface AssetRvItem : BalanceListRvItem { + val asset: AssetModel +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt new file mode 100644 index 0000000000..9428662690 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt @@ -0,0 +1,8 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items + +import io.novafoundation.nova.feature_assets.presentation.model.AssetModel +import io.novafoundation.nova.runtime.ext.fullId + +data class NetworkAssetUi(override val asset: AssetModel) : AssetRvItem { + override val id: String = asset.token.configuration.fullId.toString() +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/AssetGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkGroupUi.kt similarity index 64% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/AssetGroupUi.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkGroupUi.kt index 8d451c8823..1278e1bb4d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/AssetGroupUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkGroupUi.kt @@ -1,8 +1,11 @@ -package io.novafoundation.nova.feature_assets.presentation.balance.list.model +package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items import io.novafoundation.nova.feature_account_api.presenatation.chain.ChainUi -data class AssetGroupUi( +data class NetworkGroupUi( val chainUi: ChainUi, val groupBalanceFiat: String -) +) : AssetGroupRvItem { + + override val id: String = chainUi.id +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt new file mode 100644 index 0000000000..1fcaab65b9 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt @@ -0,0 +1,10 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items + +import io.novafoundation.nova.feature_account_api.presenatation.chain.ChainUi +import io.novafoundation.nova.feature_assets.presentation.model.AssetModel +import io.novafoundation.nova.runtime.ext.fullId + +data class TokenAssetUi(override val asset: AssetModel, val chain: ChainUi) : AssetRvItem { + + override val id: String = asset.token.configuration.fullId.toString() +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt new file mode 100644 index 0000000000..5495708178 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt @@ -0,0 +1,15 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items + +import androidx.annotation.ColorRes +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel + +data class TokenGroupUi( + val tokenIcon: String?, + val rate: String, + val recentRateChange: String, + @ColorRes val rateChangeColorRes: Int, + val tokenSymbol: String, + val balance: AmountModel +) : AssetGroupRvItem { + override val id: String = tokenSymbol +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt new file mode 100644 index 0000000000..b0eb8b1e9e --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt @@ -0,0 +1,56 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.list.view + +import android.content.Context +import android.util.AttributeSet +import android.view.Gravity +import android.view.View +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import io.novafoundation.nova.common.utils.WithContextExtensions +import io.novafoundation.nova.common.utils.setTextColorRes +import io.novafoundation.nova.feature_assets.R +import kotlinx.android.synthetic.main.view_asset_view_mode.view.assetViewModeIcon +import kotlinx.android.synthetic.main.view_asset_view_mode.view.assetViewModeText + +class AssetViewModeView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, +) : LinearLayout(context, attrs, defStyleAttr), WithContextExtensions { + + override val providedContext: Context = context + + init { + View.inflate(context, R.layout.view_asset_view_mode, this) + + orientation = HORIZONTAL + gravity = Gravity.CENTER_VERTICAL + + assetViewModeIcon.setFactory { + val imageView = ImageView(context, null, 0) + imageView.scaleType = ImageView.ScaleType.CENTER_INSIDE + imageView + } + + assetViewModeText.setFactory { + val textView = TextView(context, null, 0, R.style.TextAppearance_NovaFoundation_SemiBold_Title3) + textView.setGravity(Gravity.CLIP_VERTICAL) + textView.setTextColorRes(R.color.text_primary) + textView + } + } + + fun switchTextTo(model: AssetViewModeModel) { + switchTextTo(model.iconRes, model.textRes) + } + + fun switchTextTo(@DrawableRes iconRes: Int, @StringRes textRes: Int) { + assetViewModeIcon.setImageResource(iconRes) + assetViewModeText.setText(context.getText(textRes)) + } +} + +class AssetViewModeModel(@DrawableRes val iconRes: Int, @StringRes val textRes: Int) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetsHeaderAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetsHeaderAdapter.kt index 8b815c37c8..8f718776f8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetsHeaderAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetsHeaderAdapter.kt @@ -12,6 +12,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.Tot import io.novafoundation.nova.feature_wallet_connect_api.presentation.WalletConnectSessionsModel import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.main.item_asset_header.view.balanceListAssetPlaceholder +import kotlinx.android.synthetic.main.item_asset_header.view.balanceListAssetTitle import kotlinx.android.synthetic.main.item_asset_header.view.balanceListAvatar import kotlinx.android.synthetic.main.item_asset_header.view.balanceListCrowdloansPromoBanner import kotlinx.android.synthetic.main.item_asset_header.view.balanceListFilters @@ -48,6 +49,8 @@ class AssetsHeaderAdapter(private val handler: Handler) : RecyclerView.Adapter? = null private var crowdloanBannerVisible: Boolean = false + private var assetViewModeModel: AssetViewModeModel? = null fun setFilterIconRes(filterIconRes: Int) { this.filterIconRes = filterIconRes @@ -107,6 +111,12 @@ class AssetsHeaderAdapter(private val handler: Handler) : RecyclerView.Adapter holder.bindWalletConnect(walletConnectModel) Payload.FILTER_ICON -> holder.bindFilterIcon(filterIconRes) Payload.CROWDLOAN_BANNER_VISIBLE -> holder.bindCrowdloanBanner(crowdloanBannerVisible) + Payload.ASSET_VIEW_MODE -> holder.bindAssetViewMode(assetViewModeModel) } } } @@ -139,7 +150,8 @@ class AssetsHeaderAdapter(private val handler: Handler) : RecyclerView.Adapter?) = with(containerView) { @@ -234,4 +249,8 @@ class HeaderHolder( fun bindCrowdloanBanner(bannerVisible: Boolean) = with(containerView) { balanceListCrowdloansPromoBanner.setVisible(bannerVisible) } + + fun bindAssetViewMode(assetViewModeModel: AssetViewModeModel?) = with(containerView) { + assetViewModeModel?.let { balanceListAssetTitle.switchTextTo(assetViewModeModel) } + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt index ea28900dae..c2060f979d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt @@ -21,6 +21,7 @@ import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetGroupingDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.common.applyDefaultTo +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import kotlinx.android.synthetic.main.fragment_asset_search.searchAssetContainer import kotlinx.android.synthetic.main.fragment_asset_search.searchAssetList @@ -101,4 +102,8 @@ class AssetSearchFragment : override fun assetClicked(asset: AssetModel) { viewModel.assetClicked(asset) } + + override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { + showMessage("Not implemented yet") + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt index 367d4c3447..6c6fb62850 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt @@ -6,7 +6,7 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.AssetsRouter -import io.novafoundation.nova.feature_assets.presentation.balance.common.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import kotlinx.coroutines.flow.MutableStateFlow diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowFragment.kt index 546177c34e..d71521ad63 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowFragment.kt @@ -4,6 +4,7 @@ import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowFragment import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixinUi import javax.inject.Inject @@ -25,6 +26,10 @@ class AssetBuyFlowFragment : AssetFlowFragment() { .inject(this) } + override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { + showMessage("Not implemented yet") + } + override fun subscribe(viewModel: AssetBuyFlowViewModel) { super.subscribe(viewModel) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowViewModel.kt index 98f57ae28b..217d292c5e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowViewModel.kt @@ -4,7 +4,7 @@ import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor -import io.novafoundation.nova.feature_assets.domain.common.AssetGroup +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin @@ -35,7 +35,7 @@ class AssetBuyFlowViewModel( val buyMixin = buyMixinFactory.create(scope = this) - override fun searchAssetsFlow(): Flow>> { + override fun searchAssetsFlow(): Flow>> { return interactor.buyAssetSearch(query, externalBalancesFlow) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowViewModel.kt index 552866ea25..a65e5a957a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowViewModel.kt @@ -9,11 +9,12 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAcco import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor -import io.novafoundation.nova.feature_assets.domain.common.AssetGroup +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.balance.common.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency @@ -25,7 +26,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch class AssetFlowListModel( - val assets: List, + val assets: List, val placeholder: PlaceholderModel?, ) @@ -66,11 +67,11 @@ abstract class AssetFlowViewModel( router.back() } - abstract fun searchAssetsFlow(): Flow>> + abstract fun searchAssetsFlow(): Flow>> abstract fun assetClicked(assetModel: AssetModel) - open fun mapAssets(assets: Map>, currency: Currency): List { + open fun mapAssets(assets: Map>, currency: Currency): List { return assets.mapGroupedAssetsToUi(currency) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowFragment.kt index 7223786337..f5edf8aede 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowFragment.kt @@ -4,6 +4,7 @@ import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowFragment class AssetReceiveFlowFragment : AssetFlowFragment() { @@ -19,4 +20,8 @@ class AssetReceiveFlowFragment : AssetFlowFragment() .create(this) .inject(this) } + + override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { + showMessage("Not implemented yet") + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowViewModel.kt index 9a76d56b64..7069f5499f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowViewModel.kt @@ -4,7 +4,7 @@ import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor -import io.novafoundation.nova.feature_assets.domain.common.AssetGroup +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.AssetsRouter @@ -31,7 +31,7 @@ class AssetReceiveFlowViewModel( externalBalancesInteractor, resourceManager, ) { - override fun searchAssetsFlow(): Flow>> { + override fun searchAssetsFlow(): Flow>> { return interactor.searchAssetsFlow(query, externalBalancesFlow) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowFragment.kt index a0acd40034..b28ac4f91f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowFragment.kt @@ -4,6 +4,7 @@ import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowFragment import kotlinx.android.synthetic.main.fragment_asset_flow_search.assetFlowPlaceholder @@ -24,4 +25,8 @@ class AssetSendFlowFragment : AssetFlowFragment() { .create(this) .inject(this) } + + override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { + showMessage("Not implemented yet") + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt index c0114504de..1576b47bb6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt @@ -6,11 +6,13 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAcco import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor -import io.novafoundation.nova.feature_assets.domain.common.AssetGroup +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.TotalAndTransferableBalance import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.balance.common.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowViewModel import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload @@ -37,7 +39,7 @@ class AssetSendFlowViewModel( resourceManager, ) { - override fun searchAssetsFlow(): Flow>> { + override fun searchAssetsFlow(): Flow>> { return interactor.sendAssetSearch(query, externalBalancesFlow) } @@ -47,8 +49,8 @@ class AssetSendFlowViewModel( router.openSend(SendPayload.SpecifiedOrigin(assetPayload)) } - override fun mapAssets(assets: Map>, currency: Currency): List { - return assets.mapGroupedAssetsToUi(currency, AssetGroup::groupTransferableBalanceFiat, AssetWithOffChainBalance.Balance::transferable) + override fun mapAssets(assets: Map>, currency: Currency): List { + return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, TotalAndTransferableBalance::transferable) } override fun getPlaceholder(query: String, assets: List): PlaceholderModel? { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowFragment.kt index 464c7fb33a..f852418309 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowFragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowFragment class AssetSwapFlowFragment : AssetFlowFragment() { @@ -30,4 +31,8 @@ class AssetSwapFlowFragment : AssetFlowFragment() { .create(this, argument(KEY_PAYLOAD)) .inject(this) } + + override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { + showMessage("Not implemented yet") + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt index 53635a063f..ad84bc9623 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt @@ -7,11 +7,13 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAcco import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor -import io.novafoundation.nova.feature_assets.domain.common.AssetGroup +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.TotalAndTransferableBalance import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.balance.common.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowViewModel import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.swap.executor.SwapFlowExecutor @@ -57,7 +59,7 @@ class AssetSwapFlowViewModel( } } - override fun searchAssetsFlow(): Flow>> { + override fun searchAssetsFlow(): Flow>> { return interactor.searchSwapAssetsFlow( forAsset = payload.constraintDirectionsAsset?.fullChainAssetId, queryFlow = query, @@ -73,7 +75,7 @@ class AssetSwapFlowViewModel( } } - override fun mapAssets(assets: Map>, currency: Currency): List { - return assets.mapGroupedAssetsToUi(currency, AssetGroup::groupTransferableBalanceFiat, AssetWithOffChainBalance.Balance::transferable) + override fun mapAssets(assets: Map>, currency: Currency): List { + return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, TotalAndTransferableBalance::transferable) } } diff --git a/feature-assets/src/main/res/layout/fragment_asset_flow_search.xml b/feature-assets/src/main/res/layout/fragment_asset_flow_search.xml index c76c465a0f..86bf06c615 100644 --- a/feature-assets/src/main/res/layout/fragment_asset_flow_search.xml +++ b/feature-assets/src/main/res/layout/fragment_asset_flow_search.xml @@ -24,7 +24,7 @@ android:paddingTop="12dp" android:paddingBottom="24dp" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - tools:listitem="@layout/item_asset" /> + tools:listitem="@layout/item_network_asset" /> + tools:listitem="@layout/item_network_asset" /> + tools:listitem="@layout/item_network_asset" /> diff --git a/feature-assets/src/main/res/layout/item_asset_header.xml b/feature-assets/src/main/res/layout/item_asset_header.xml index 253adb5639..3c1fcadea1 100644 --- a/feature-assets/src/main/res/layout/item_asset_header.xml +++ b/feature-assets/src/main/res/layout/item_asset_header.xml @@ -73,18 +73,16 @@ android:layout_marginTop="12dp" app:layout_constraintTop_toBottomOf="@id/balanceListNfts" /> - + + + + + + + + + + + + + + + + + + + + diff --git a/feature-assets/src/main/res/layout/item_token_asset_group.xml b/feature-assets/src/main/res/layout/item_token_asset_group.xml new file mode 100644 index 0000000000..f4031dd6b4 --- /dev/null +++ b/feature-assets/src/main/res/layout/item_token_asset_group.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + diff --git a/feature-assets/src/main/res/layout/view_asset_view_mode.xml b/feature-assets/src/main/res/layout/view_asset_view_mode.xml new file mode 100644 index 0000000000..598c790f21 --- /dev/null +++ b/feature-assets/src/main/res/layout/view_asset_view_mode.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/ext/TokenSorting.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/ext/TokenSorting.kt new file mode 100644 index 0000000000..33640bfa7d --- /dev/null +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/ext/TokenSorting.kt @@ -0,0 +1,18 @@ +package io.novafoundation.nova.runtime.ext + +import io.novafoundation.nova.common.utils.TokenSymbol + +val TokenSymbol.mainTokensFirstAscendingOrder + get() = when (this.value) { + "DOT" -> 0 + "KSM" -> 1 + else -> 2 + } + +val TokenSymbol.alphabeticalOrder + get() = value + +fun TokenSymbol.Companion.defaultComparatorFrom(extractor: (K) -> TokenSymbol): Comparator = Comparator.comparing(extractor, defaultComparator()) + +fun TokenSymbol.Companion.defaultComparator(): Comparator = compareBy { it.mainTokensFirstAscendingOrder } + .thenBy { it.alphabeticalOrder } From a6b27fbc35cc9b913ea23cdb56697a23face6933 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 17 Oct 2024 12:10:59 +0200 Subject: [PATCH 02/78] Added payloads support for items in asset list --- .../balance/common/BalanceListAdapter.kt | 60 +++++++++++++++---- .../common/holders/NetworkAssetViewHolder.kt | 16 +++-- .../holders/TokenAssetGroupViewHolder.kt | 4 +- .../common/holders/TokenAssetViewHolder.kt | 6 +- 4 files changed, 61 insertions(+), 25 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt index b3543cf310..880ea7956f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt @@ -21,9 +21,13 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.ite import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel -private val priceRateExtractor = { assetModel: NetworkAssetUi -> assetModel.asset.token.rate } -private val recentChangeExtractor = { assetModel: NetworkAssetUi -> assetModel.asset.token.recentRateChange } -private val amountExtractor = { assetModel: NetworkAssetUi -> assetModel.asset.amount } +private val priceRateExtractor = { asset: AssetModel -> asset.token.rate } +private val recentChangeExtractor = { asset: AssetModel -> asset.token.recentRateChange } +private val amountExtractor = { asset: AssetModel -> asset.amount } + +private val tokenGroupPriceRateExtractor = { group: TokenGroupUi -> group.rate } +private val tokenGroupRecentChangeExtractor = { group: TokenGroupUi -> group.recentRateChange } +private val tokenGroupAmountExtractor = { group: TokenGroupUi -> group.balance } const val TYPE_NETWORK_GROUP = 0 const val TYPE_NETWORK_ASSET = 1 @@ -67,9 +71,29 @@ class BalanceListAdapter( val item = getItem(position) as NetworkAssetUi resolvePayload(holder, position, payloads) { when (it) { - priceRateExtractor -> holder.bindPriceInfo(item) - recentChangeExtractor -> holder.bindRecentChange(item) - AssetModel::amount -> holder.bindTotal(item) + priceRateExtractor -> holder.bindPriceInfo(item.asset) + recentChangeExtractor -> holder.bindRecentChange(item.asset) + amountExtractor -> holder.bindTotal(item.asset) + } + } + } + + is TokenAssetViewHolder -> { + val item = getItem(position) as NetworkAssetUi + resolvePayload(holder, position, payloads) { + when (it) { + AssetModel::amount -> holder.bindTotal(item.asset) + } + } + } + + is TokenAssetGroupViewHolder -> { + val item = getItem(position) as TokenGroupUi + resolvePayload(holder, position, payloads) { + when (it) { + tokenGroupPriceRateExtractor -> holder.bindPriceRate(item) + tokenGroupRecentChangeExtractor -> holder.bindRecentChange(item) + tokenGroupAmountExtractor -> holder.bindTotal(item) } } } @@ -101,16 +125,30 @@ private object DiffCallback : DiffUtil.ItemCallback() { } override fun getChangePayload(oldItem: BalanceListRvItem, newItem: BalanceListRvItem): Any? { - if (oldItem is NetworkAssetUi && newItem is NetworkAssetUi) { - return AssetPayloadGenerator.diff(oldItem, newItem) - } + return when { + oldItem is NetworkAssetUi && newItem is NetworkAssetUi -> NetworkAssetPayloadGenerator.diff(oldItem.asset, newItem.asset) - return null + oldItem is TokenAssetUi && newItem is TokenAssetUi -> TokenAssetPayloadGenerator.diff(oldItem.asset, newItem.asset) + + oldItem is TokenGroupUi && newItem is TokenGroupUi -> TokenGroupAssetPayloadGenerator.diff(oldItem, newItem) + + else -> null + } } } -private object AssetPayloadGenerator : PayloadGenerator( +private object NetworkAssetPayloadGenerator : PayloadGenerator( priceRateExtractor, recentChangeExtractor, amountExtractor ) + +private object TokenAssetPayloadGenerator : PayloadGenerator( + amountExtractor +) + +private object TokenGroupAssetPayloadGenerator : PayloadGenerator( + tokenGroupPriceRateExtractor, + tokenGroupRecentChangeExtractor, + tokenGroupAmountExtractor +) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt index a0fb56fe45..36e8d75d6d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt @@ -7,6 +7,7 @@ import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkAssetUi +import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import kotlinx.android.synthetic.main.item_network_asset.view.itemAssetBalance import kotlinx.android.synthetic.main.item_network_asset.view.itemAssetImage import kotlinx.android.synthetic.main.item_network_asset.view.itemAssetPriceAmount @@ -23,31 +24,28 @@ class NetworkAssetViewHolder( val asset = networkAsset.asset itemAssetImage.loadTokenIcon(asset.token.configuration.iconUrl, imageLoader) - bindPriceInfo(networkAsset) + bindPriceInfo(asset) - bindRecentChange(networkAsset) + bindRecentChange(asset) - bindTotal(networkAsset) + bindTotal(asset) itemAssetToken.text = asset.token.configuration.symbol.value setOnClickListener { itemHandler.assetClicked(asset) } } - fun bindTotal(networkAsset: NetworkAssetUi) { - val asset = networkAsset.asset + fun bindTotal(asset: AssetModel) { containerView.itemAssetBalance.text = asset.amount.token containerView.itemAssetPriceAmount.text = asset.amount.fiat } - fun bindRecentChange(networkAsset: NetworkAssetUi) = with(containerView) { - val asset = networkAsset.asset + fun bindRecentChange(asset: AssetModel) = with(containerView) { itemAssetRateChange.setTextColorRes(asset.token.rateChangeColorRes) itemAssetRateChange.text = asset.token.recentRateChange } - fun bindPriceInfo(networkAsset: NetworkAssetUi) = with(containerView) { - val asset = networkAsset.asset + fun bindPriceInfo(asset: AssetModel) = with(containerView) { itemAssetRate.text = asset.token.rate } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt index 6915ab54dd..13703413d8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt @@ -22,7 +22,7 @@ class TokenAssetGroupViewHolder( fun bind(tokenGroup: TokenGroupUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { itemTokenGroupAssetImage.loadTokenIcon(tokenGroup.tokenIcon, imageLoader) - bindPriceInfo(tokenGroup) + bindPriceRate(tokenGroup) bindRecentChange(tokenGroup) @@ -44,7 +44,7 @@ class TokenAssetGroupViewHolder( itemAssetTokenGroupRateChange.text = networkAsset.recentRateChange } - fun bindPriceInfo(networkAsset: TokenGroupUi) = with(containerView) { + fun bindPriceRate(networkAsset: TokenGroupUi) = with(containerView) { itemAssetTokenGroupRate.text = networkAsset.rate } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt index 667a59da57..86e4dd9b9e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt @@ -6,6 +6,7 @@ import io.novafoundation.nova.common.list.GroupedListHolder import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi +import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import kotlinx.android.synthetic.main.item_token_asset.view.itemTokenAssetImage import kotlinx.android.synthetic.main.item_token_asset.view.itemTokenAssetToken import kotlinx.android.synthetic.main.item_token_asset.view.itemTokenAssetBalance @@ -24,15 +25,14 @@ class TokenAssetViewHolder( itemTokenAssetChainIcon.loadTokenIcon(tokenAsset.chain.icon, imageLoader) itemTokenAssetChainName.text = tokenAsset.chain.name - bindTotal(tokenAsset) + bindTotal(asset) itemTokenAssetToken.text = asset.token.configuration.symbol.value setOnClickListener { itemHandler.assetClicked(asset) } } - fun bindTotal(networkAsset: TokenAssetUi) { - val asset = networkAsset.asset + fun bindTotal(asset: AssetModel) { containerView.itemTokenAssetBalance.text = asset.amount.token containerView.itemTokenAssetPriceAmount.text = asset.amount.fiat } From 727f4b03b65398a6c15f7f8d621b78e030c9a1f2 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 17 Oct 2024 12:28:28 +0200 Subject: [PATCH 03/78] Clean code --- .../balance/common/AssetListMixin.kt | 18 ++++++++--- .../balance/common/BalanceListAdapter.kt | 2 +- .../common/mappers/AssetMappersCommon.kt | 30 +++++++++++++++++++ .../common/mappers/NetworkAssetMappers.kt | 30 ------------------- .../balance/list/BalanceListFragment.kt | 2 +- .../balance/list/BalanceListViewModel.kt | 2 +- 6 files changed, 47 insertions(+), 37 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index 84e7d724bf..bf235f7a33 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common import io.novafoundation.nova.common.data.model.AssetViewMode import io.novafoundation.nova.common.data.model.switch +import io.novafoundation.nova.common.utils.shareInBackground import io.novafoundation.nova.common.utils.toggle import io.novafoundation.nova.common.utils.updateValue import io.novafoundation.nova.feature_assets.domain.WalletInteractor @@ -14,6 +15,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.ite import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_wallet_api.domain.model.Asset +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine @@ -27,11 +29,12 @@ class AssetListMixinFactory( private val externalBalancesInteractor: ExternalBalancesInteractor ) { - fun create(): AssetListMixin = RealAssetListMixin( + fun create(coroutineScope: CoroutineScope): AssetListMixin = RealAssetListMixin( walletInteractor, assetsListInteractor, currencyInteractor, - externalBalancesInteractor + externalBalancesInteractor, + coroutineScope ) } @@ -52,20 +55,26 @@ class RealAssetListMixin( private val walletInteractor: WalletInteractor, private val assetsListInteractor: AssetsListInteractor, private val currencyInteractor: CurrencyInteractor, - private val externalBalancesInteractor: ExternalBalancesInteractor -) : AssetListMixin { + private val externalBalancesInteractor: ExternalBalancesInteractor, + private val coroutineScope: CoroutineScope +) : AssetListMixin, CoroutineScope by coroutineScope { override val assetsFlow = walletInteractor.assetsFlow() + .shareInBackground() override val filteredAssetsFlow = walletInteractor.filterAssets(assetsFlow) + .shareInBackground() private val selectedCurrency = currencyInteractor.observeSelectCurrency() + .shareInBackground() private val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() + .shareInBackground() private val expandedTokenIdsFlow = MutableStateFlow(setOf()) override val assetsViewModeFlow = assetsListInteractor.assetsViewModeFlow() + .shareInBackground() override val assetModelsFlow = combine( filteredAssetsFlow, @@ -81,6 +90,7 @@ class RealAssetListMixin( .mapGroupedAssetsToUi() } }.distinctUntilChanged() + .shareInBackground() override suspend fun switchViewMode() { val assetViewMode = assetsViewModeFlow.first() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt index 880ea7956f..b17ae1c29a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt @@ -79,7 +79,7 @@ class BalanceListAdapter( } is TokenAssetViewHolder -> { - val item = getItem(position) as NetworkAssetUi + val item = getItem(position) as TokenAssetUi resolvePayload(holder, position, payloads) { when (it) { AssetModel::amount -> holder.bindTotal(item.asset) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt index ef514c3235..524a814cdc 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt @@ -1,13 +1,21 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mappers +import androidx.annotation.ColorRes +import io.novafoundation.nova.common.utils.formatting.formatAsChange +import io.novafoundation.nova.common.utils.isNonNegative +import io.novafoundation.nova.common.utils.isZero import io.novafoundation.nova.common.utils.orZero +import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.common.Amount import io.novafoundation.nova.feature_assets.presentation.model.AssetModel +import io.novafoundation.nova.feature_assets.presentation.model.TokenModel import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.CoinRateChange +import io.novafoundation.nova.feature_wallet_api.domain.model.Token import io.novafoundation.nova.feature_wallet_api.presentation.model.mapAmountToAmountModel +import java.math.BigDecimal fun mapCoinRateChange(coinRateChange: CoinRateChange?, currency: Currency): String { val rateChange = coinRateChange?.rate @@ -27,3 +35,25 @@ fun mapAssetToAssetModel( ) ) } + +@ColorRes +fun mapCoinRateChangeColorRes(coinRateChange: CoinRateChange?): Int { + val rateChange = coinRateChange?.recentRateChange + + return when { + rateChange == null || rateChange.isZero -> R.color.text_secondary + rateChange.isNonNegative -> R.color.text_positive + else -> R.color.text_negative + } +} + +fun mapTokenToTokenModel(token: Token): TokenModel { + return with(token) { + TokenModel( + configuration = configuration, + rate = mapCoinRateChange(token.coinRate, token.currency), + recentRateChange = (coinRate?.recentRateChange ?: BigDecimal.ZERO).formatAsChange(), + rateChangeColorRes = mapCoinRateChangeColorRes(coinRate) + ) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt index e3a2e5327a..c352bb6d15 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt @@ -1,13 +1,8 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mappers -import androidx.annotation.ColorRes import io.novafoundation.nova.common.list.GroupedList import io.novafoundation.nova.common.list.toListWithHeaders -import io.novafoundation.nova.common.utils.formatting.formatAsChange -import io.novafoundation.nova.common.utils.isNonNegative -import io.novafoundation.nova.common.utils.isZero import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi -import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.common.Amount import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance @@ -15,11 +10,8 @@ import io.novafoundation.nova.feature_assets.domain.common.TotalAndTransferableB import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkAssetUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkGroupUi -import io.novafoundation.nova.feature_assets.presentation.model.TokenModel import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency -import io.novafoundation.nova.feature_wallet_api.domain.model.CoinRateChange -import io.novafoundation.nova.feature_wallet_api.domain.model.Token import java.math.BigDecimal fun GroupedList.mapGroupedAssetsToUi( @@ -33,28 +25,6 @@ fun GroupedList.mapGroupedAssetsToU .filterIsInstance() } -fun mapTokenToTokenModel(token: Token): TokenModel { - return with(token) { - TokenModel( - configuration = configuration, - rate = mapCoinRateChange(token.coinRate, token.currency), - recentRateChange = (coinRate?.recentRateChange ?: BigDecimal.ZERO).formatAsChange(), - rateChangeColorRes = mapCoinRateChangeColorRes(coinRate) - ) - } -} - -@ColorRes -fun mapCoinRateChangeColorRes(coinRateChange: CoinRateChange?): Int { - val rateChange = coinRateChange?.recentRateChange - - return when { - rateChange == null || rateChange.isZero -> R.color.text_secondary - rateChange.isNonNegative -> R.color.text_positive - else -> R.color.text_negative - } -} - private fun mapAssetsToAssetModels( assets: List, balance: (TotalAndTransferableBalance) -> Amount diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index 6277b1b41f..40ff44eefb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -139,7 +139,7 @@ class BalanceListFragment : } override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { - showMessage("Not implemented yet") + viewModel.assetListMixin.expandToken(tokenGroup) } override fun totalBalanceClicked() { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt index a85fb30ace..8407170880 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt @@ -93,7 +93,7 @@ class BalanceListViewModel( private val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() - val assetListMixin = assetListMixinFactory.create() + val assetListMixin = assetListMixinFactory.create(viewModelScope) private val isFiltersEnabledFlow = walletInteractor.isFiltersEnabledFlow() From d02b119ad0835bf2d802e36675444fcdf5c40355 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 17 Oct 2024 13:51:32 +0200 Subject: [PATCH 04/78] Move zero balances filter --- .../nova/app/root/navigation/Navigator.kt | 4 -- .../main/res/navigation/main_nav_graph.xml | 13 ---- .../di/AssetsFeatureComponent.kt | 3 - .../presentation/AssetsRouter.kt | 2 - .../AssetFiltersBottomSheetFragment.kt | 39 ----------- .../balance/filters/AssetFiltersViewModel.kt | 55 ---------------- .../filters/di/AssetFiltersComponent.kt | 26 -------- .../balance/filters/di/AssetFiltersModule.kt | 43 ------------- .../balance/list/BalanceListFragment.kt | 4 -- .../balance/list/BalanceListViewModel.kt | 4 -- .../balance/list/view/AssetsHeaderAdapter.kt | 14 +--- .../tokens/manage/ManageTokensFragment.kt | 7 ++ .../tokens/manage/ManageTokensViewModel.kt | 46 ++++++++++++- .../tokens/manage/di/ManageTokensModule.kt | 15 ++++- .../res/layout/fragment_asset_filters.xml | 1 - .../res/layout/fragment_manage_tokens.xml | 64 +++++++++++++------ .../src/main/res/layout/item_asset_header.xml | 14 +--- 17 files changed, 113 insertions(+), 241 deletions(-) delete mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/AssetFiltersBottomSheetFragment.kt delete mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/AssetFiltersViewModel.kt delete mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/di/AssetFiltersComponent.kt delete mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/di/AssetFiltersModule.kt diff --git a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt index c08822e2a5..1c4b392e58 100644 --- a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt +++ b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt @@ -323,10 +323,6 @@ class Navigator( navController?.navigate(R.id.action_open_receive, ReceiveFragment.getBundle(assetPayload)) } - override fun openAssetFilters() { - navController?.navigate(R.id.action_mainFragment_to_assetFiltersFragment) - } - override fun openAssetSearch() { navController?.navigate(R.id.action_mainFragment_to_assetSearchFragment) } diff --git a/app/src/main/res/navigation/main_nav_graph.xml b/app/src/main/res/navigation/main_nav_graph.xml index 8efb8f4078..7c8b340124 100644 --- a/app/src/main/res/navigation/main_nav_graph.xml +++ b/app/src/main/res/navigation/main_nav_graph.xml @@ -365,14 +365,6 @@ app:popEnterAnim="@anim/fragment_close_enter" app:popExitAnim="@anim/fragment_close_exit" /> - - - - () { - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ) = layoutInflater.inflate(R.layout.fragment_asset_filters, container, false) - - override fun initViews() {} - - override fun inject() { - FeatureUtils.getFeature( - requireContext(), - AssetsFeatureApi::class.java - ) - .assetFiltersComponentFactory() - .create(this) - .inject(this) - } - - override fun subscribe(viewModel: AssetFiltersViewModel) { - assetsFilterSwitchZeroBalances.bindFromMap(NonZeroBalanceFilter, viewModel.filtersEnabledMap, viewLifecycleOwner.lifecycleScope) - } -} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/AssetFiltersViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/AssetFiltersViewModel.kt deleted file mode 100644 index dc5ac10761..0000000000 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/AssetFiltersViewModel.kt +++ /dev/null @@ -1,55 +0,0 @@ -package io.novafoundation.nova.feature_assets.presentation.balance.filters - -import io.novafoundation.nova.common.base.BaseViewModel -import io.novafoundation.nova.common.utils.checkEnabled -import io.novafoundation.nova.common.utils.combineIdentity -import io.novafoundation.nova.common.utils.flowOf -import io.novafoundation.nova.common.utils.inBackground -import io.novafoundation.nova.feature_assets.domain.assets.filters.AssetFilter -import io.novafoundation.nova.feature_assets.domain.assets.filters.AssetFiltersInteractor -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.drop -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch - -class AssetFiltersViewModel( - private val interactor: AssetFiltersInteractor, -) : BaseViewModel() { - - private val initialFilters = flowOf { interactor.currentFilters() } - .inBackground() - .share() - - val filtersEnabledMap = createFilterEnabledMap() - - init { - applyInitialState() - filtersEnabledMap.applyOnChange() - } - - private fun applyInitialState() = launch { - val initialFilters = initialFilters.first() - - filtersEnabledMap.forEach { (filter, checked) -> - checked.value = filter in initialFilters - } - } - - private fun createFilterEnabledMap() = interactor.allFilters.associateWith { MutableStateFlow(false) } - - private fun Map>.applyOnChange() { - combineIdentity(this.values) - .drop(1) - .onEach { - applyChanges() - } - .launchIn(this@AssetFiltersViewModel) - } - - private fun applyChanges() { - val filters = interactor.allFilters.filter(filtersEnabledMap::checkEnabled) - interactor.updateFilters(filters) - } -} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/di/AssetFiltersComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/di/AssetFiltersComponent.kt deleted file mode 100644 index d377cd4429..0000000000 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/di/AssetFiltersComponent.kt +++ /dev/null @@ -1,26 +0,0 @@ -package io.novafoundation.nova.feature_assets.presentation.balance.filters.di - -import androidx.fragment.app.Fragment -import dagger.BindsInstance -import dagger.Subcomponent -import io.novafoundation.nova.common.di.scope.ScreenScope -import io.novafoundation.nova.feature_assets.presentation.balance.filters.AssetFiltersBottomSheetFragment - -@Subcomponent( - modules = [ - AssetFiltersModule::class - ] -) -@ScreenScope -interface AssetFiltersComponent { - - @Subcomponent.Factory - interface Factory { - - fun create( - @BindsInstance fragment: Fragment, - ): AssetFiltersComponent - } - - fun inject(fragment: AssetFiltersBottomSheetFragment) -} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/di/AssetFiltersModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/di/AssetFiltersModule.kt deleted file mode 100644 index 12ae0fe7e5..0000000000 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/filters/di/AssetFiltersModule.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.novafoundation.nova.feature_assets.presentation.balance.filters.di - -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import dagger.Module -import dagger.Provides -import dagger.multibindings.IntoMap -import io.novafoundation.nova.common.di.scope.ScreenScope -import io.novafoundation.nova.common.di.viewmodel.ViewModelKey -import io.novafoundation.nova.common.di.viewmodel.ViewModelModule -import io.novafoundation.nova.feature_assets.data.repository.assetFilters.AssetFiltersRepository -import io.novafoundation.nova.feature_assets.domain.assets.filters.AssetFiltersInteractor -import io.novafoundation.nova.feature_assets.presentation.balance.filters.AssetFiltersViewModel - -@Module(includes = [ViewModelModule::class]) -class AssetFiltersModule { - - @Provides - @ScreenScope - fun provideInteractor( - assetFiltersRepository: AssetFiltersRepository - ) = AssetFiltersInteractor(assetFiltersRepository) - - @Provides - @IntoMap - @ViewModelKey(AssetFiltersViewModel::class) - fun provideViewModel( - interactor: AssetFiltersInteractor, - ): ViewModel { - return AssetFiltersViewModel( - interactor = interactor, - ) - } - - @Provides - fun provideViewModelCreator( - fragment: Fragment, - viewModelFactory: ViewModelProvider.Factory - ): AssetFiltersViewModel { - return ViewModelProvider(fragment, viewModelFactory).get(AssetFiltersViewModel::class.java) - } -} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index 40ff44eefb..ae91f1844f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -154,10 +154,6 @@ class BalanceListFragment : viewModel.searchClicked() } - override fun filtersClicked() { - viewModel.filtersClicked() - } - override fun avatarClicked() { viewModel.avatarClicked() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt index 8407170880..ccae284ee6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt @@ -216,10 +216,6 @@ class BalanceListViewModel( router.openSwitchWallet() } - fun filtersClicked() { - router.openAssetFilters() - } - fun manageClicked() { router.openManageTokens() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetsHeaderAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetsHeaderAdapter.kt index 8f718776f8..23731ab55d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetsHeaderAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetsHeaderAdapter.kt @@ -15,7 +15,6 @@ import kotlinx.android.synthetic.main.item_asset_header.view.balanceListAssetPla import kotlinx.android.synthetic.main.item_asset_header.view.balanceListAssetTitle import kotlinx.android.synthetic.main.item_asset_header.view.balanceListAvatar import kotlinx.android.synthetic.main.item_asset_header.view.balanceListCrowdloansPromoBanner -import kotlinx.android.synthetic.main.item_asset_header.view.balanceListFilters import kotlinx.android.synthetic.main.item_asset_header.view.balanceListManage import kotlinx.android.synthetic.main.item_asset_header.view.balanceListNfts import kotlinx.android.synthetic.main.item_asset_header.view.balanceListSearch @@ -29,7 +28,7 @@ class AssetsHeaderAdapter(private val handler: Handler) : RecyclerView.Adapter holder.bindNftPreviews(nftPreviews) Payload.PLACEHOLDER -> holder.bindPlaceholder(shouldShowPlaceholder) Payload.WALLET_CONNECT -> holder.bindWalletConnect(walletConnectModel) - Payload.FILTER_ICON -> holder.bindFilterIcon(filterIconRes) Payload.CROWDLOAN_BANNER_VISIBLE -> holder.bindCrowdloanBanner(crowdloanBannerVisible) Payload.ASSET_VIEW_MODE -> holder.bindAssetViewMode(assetViewModeModel) } @@ -161,7 +157,7 @@ class AssetsHeaderAdapter(private val handler: Handler) : RecyclerView.Adapter(), @@ -52,6 +55,8 @@ class ManageTokensFragment : } } + manageTokensSwitchZeroBalances.setOnClickListener { viewModel.zeroBalancesClicked() } + manageTokensList.setHasFixedSize(true) manageTokensList.adapter = tokensAdapter @@ -62,6 +67,8 @@ class ManageTokensFragment : manageTokensSearch.requestFocus() manageTokensSearch.content.showSoftKeyboard() + + manageTokensSwitchZeroBalances.bindFromMap(NonZeroBalanceFilter, viewModel.filtersEnabledMap, viewLifecycleOwner.lifecycleScope) } override fun inject() { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensViewModel.kt index c592a80b9c..bc8c9e2ca5 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensViewModel.kt @@ -1,7 +1,14 @@ package io.novafoundation.nova.feature_assets.presentation.tokens.manage +import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.utils.checkEnabled +import io.novafoundation.nova.common.utils.combineIdentity +import io.novafoundation.nova.common.utils.flowOf +import io.novafoundation.nova.common.utils.inBackground import io.novafoundation.nova.common.utils.mapList +import io.novafoundation.nova.feature_assets.domain.assets.filters.AssetFilter +import io.novafoundation.nova.feature_assets.domain.assets.filters.AssetFiltersInteractor import io.novafoundation.nova.feature_assets.domain.tokens.manage.ManageTokenInteractor import io.novafoundation.nova.feature_assets.domain.tokens.manage.MultiChainToken import io.novafoundation.nova.feature_assets.domain.tokens.manage.allChainAssetIds @@ -11,15 +18,25 @@ import io.novafoundation.nova.feature_assets.presentation.tokens.manage.chain.Ma import io.novafoundation.nova.feature_assets.presentation.tokens.manage.model.MultiChainTokenMapper import io.novafoundation.nova.feature_assets.presentation.tokens.manage.model.MultiChainTokenModel import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch class ManageTokensViewModel( private val router: AssetsRouter, private val interactor: ManageTokenInteractor, - private val commonUiMapper: MultiChainTokenMapper + private val commonUiMapper: MultiChainTokenMapper, + private val assetFiltersInteractor: AssetFiltersInteractor, ) : BaseViewModel() { + private val initialFilters = flowOf { assetFiltersInteractor.currentFilters() } + .inBackground() + .share() + + val filtersEnabledMap = assetFiltersInteractor.allFilters.associateWith { MutableStateFlow(false) } + val query = MutableStateFlow("") private val multiChainTokensFlow = interactor.multiChainTokensFlow(query) @@ -29,6 +46,10 @@ class ManageTokensViewModel( .mapList(::mapMultiChainTokenToUi) .shareInBackground() + init { + applyFiltersInitialState() + } + fun closeClicked() { router.back() } @@ -53,6 +74,9 @@ class ManageTokensViewModel( ) } + fun zeroBalancesClicked() { + } + private suspend fun getMultiChainTokenAt(position: Int): MultiChainToken? { return multiChainTokensFlow.first().getOrNull(position) } @@ -64,4 +88,24 @@ class ManageTokensViewModel( switchable = multiChainToken.isSwitchable ) } + + private fun applyFiltersInitialState() = launch { + val initialFilters = initialFilters.first() + + filtersEnabledMap.forEach { (filter, checked) -> + checked.value = filter in initialFilters + } + + filtersEnabledMap.applyOnChange() + } + + private fun Map>.applyOnChange() { + combineIdentity(this.values) + .drop(1) + .onEach { + val enabledFilters = assetFiltersInteractor.allFilters.filter(filtersEnabledMap::checkEnabled) + assetFiltersInteractor.updateFilters(enabledFilters) + } + .launchIn(viewModelScope) + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/di/ManageTokensModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/di/ManageTokensModule.kt index 28ff5f778a..7374b7e54a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/di/ManageTokensModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/di/ManageTokensModule.kt @@ -6,8 +6,11 @@ import androidx.lifecycle.ViewModelProvider import dagger.Module import dagger.Provides import dagger.multibindings.IntoMap +import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.feature_assets.data.repository.assetFilters.AssetFiltersRepository +import io.novafoundation.nova.feature_assets.domain.assets.filters.AssetFiltersInteractor import io.novafoundation.nova.feature_assets.domain.tokens.manage.ManageTokenInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.tokens.manage.ManageTokensViewModel @@ -16,6 +19,12 @@ import io.novafoundation.nova.feature_assets.presentation.tokens.manage.model.Mu @Module(includes = [ViewModelModule::class]) class ManageTokensModule { + @Provides + @ScreenScope + fun provideAssetFiltersInteractor( + assetFiltersRepository: AssetFiltersRepository + ) = AssetFiltersInteractor(assetFiltersRepository) + @Provides internal fun provideViewModel(fragment: Fragment, factory: ViewModelProvider.Factory): ManageTokensViewModel { return ViewModelProvider(fragment, factory).get(ManageTokensViewModel::class.java) @@ -27,12 +36,14 @@ class ManageTokensModule { fun provideViewModel( router: AssetsRouter, interactor: ManageTokenInteractor, - commonUiMapper: MultiChainTokenMapper + commonUiMapper: MultiChainTokenMapper, + assetFiltersInteractor: AssetFiltersInteractor ): ViewModel { return ManageTokensViewModel( router = router, interactor = interactor, - commonUiMapper = commonUiMapper + commonUiMapper = commonUiMapper, + assetFiltersInteractor = assetFiltersInteractor ) } } diff --git a/feature-assets/src/main/res/layout/fragment_asset_filters.xml b/feature-assets/src/main/res/layout/fragment_asset_filters.xml index c4479e02e0..125490b1f0 100644 --- a/feature-assets/src/main/res/layout/fragment_asset_filters.xml +++ b/feature-assets/src/main/res/layout/fragment_asset_filters.xml @@ -1,6 +1,5 @@ - - - + android:background="@color/solid_navigation_background" + android:orientation="vertical" + app:layout_constraintTop_toTopOf="parent"> + + + + + + + + + @@ -46,14 +71,13 @@ android:id="@+id/manageTokensList" android:layout_width="match_parent" android:layout_height="0dp" - android:layout_marginTop="8dp" android:layout_weight="1" android:clipToPadding="false" android:paddingTop="8dp" android:paddingBottom="16dp" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintTop_toBottomOf="@id/manageTokensSearch" + app:layout_constraintTop_toBottomOf="@id/manageTokensToolbarContainer" tools:listitem="@layout/item_manage_token_multichain" /> \ No newline at end of file diff --git a/feature-assets/src/main/res/layout/item_asset_header.xml b/feature-assets/src/main/res/layout/item_asset_header.xml index 3c1fcadea1..af0239a2fa 100644 --- a/feature-assets/src/main/res/layout/item_asset_header.xml +++ b/feature-assets/src/main/res/layout/item_asset_header.xml @@ -91,20 +91,10 @@ android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:src="@drawable/ic_search" - app:layout_constraintBottom_toBottomOf="@+id/balanceListFilters" - app:layout_constraintEnd_toStartOf="@+id/balanceListFilters" - app:layout_constraintTop_toTopOf="@+id/balanceListFilters" - app:tint="@color/chip_icon" /> - - + app:layout_constraintTop_toTopOf="@+id/balanceListManage" + app:tint="@color/chip_icon" /> Date: Thu, 17 Oct 2024 13:56:55 +0200 Subject: [PATCH 05/78] Clean code --- .../tokens/manage/ManageTokensFragment.kt | 2 -- .../tokens/manage/ManageTokensViewModel.kt | 11 +---------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensFragment.kt index 5f5f238081..4bec00e171 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensFragment.kt @@ -55,8 +55,6 @@ class ManageTokensFragment : } } - manageTokensSwitchZeroBalances.setOnClickListener { viewModel.zeroBalancesClicked() } - manageTokensList.setHasFixedSize(true) manageTokensList.adapter = tokensAdapter diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensViewModel.kt index bc8c9e2ca5..f85007b99c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensViewModel.kt @@ -4,8 +4,6 @@ import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.base.BaseViewModel import io.novafoundation.nova.common.utils.checkEnabled import io.novafoundation.nova.common.utils.combineIdentity -import io.novafoundation.nova.common.utils.flowOf -import io.novafoundation.nova.common.utils.inBackground import io.novafoundation.nova.common.utils.mapList import io.novafoundation.nova.feature_assets.domain.assets.filters.AssetFilter import io.novafoundation.nova.feature_assets.domain.assets.filters.AssetFiltersInteractor @@ -31,10 +29,6 @@ class ManageTokensViewModel( private val assetFiltersInteractor: AssetFiltersInteractor, ) : BaseViewModel() { - private val initialFilters = flowOf { assetFiltersInteractor.currentFilters() } - .inBackground() - .share() - val filtersEnabledMap = assetFiltersInteractor.allFilters.associateWith { MutableStateFlow(false) } val query = MutableStateFlow("") @@ -74,9 +68,6 @@ class ManageTokensViewModel( ) } - fun zeroBalancesClicked() { - } - private suspend fun getMultiChainTokenAt(position: Int): MultiChainToken? { return multiChainTokensFlow.first().getOrNull(position) } @@ -90,7 +81,7 @@ class ManageTokensViewModel( } private fun applyFiltersInitialState() = launch { - val initialFilters = initialFilters.first() + val initialFilters = assetFiltersInteractor.currentFilters() filtersEnabledMap.forEach { (filter, checked) -> checked.value = filter in initialFilters From 783a785984b536dc01381aefe1f2cecc106efde5 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 18 Oct 2024 10:38:26 +0200 Subject: [PATCH 06/78] Switcher animation --- ...et_mode_out.xml => asset_mode_fade_in.xml} | 1 - ...et_mode_in.xml => asset_mode_fade_out.xml} | 1 - .../res/anim/asset_mode_slide_bottom_in.xml | 9 +++ .../res/anim/asset_mode_slide_bottom_out.xml | 9 +++ .../main/res/anim/asset_mode_slide_top_in.xml | 9 +++ .../res/anim/asset_mode_slide_top_out.xml | 9 +++ .../balance/list/BalanceListViewModel.kt | 3 +- .../balance/list/view/AssetViewModeView.kt | 55 ++++++++++++++++++- .../main/res/layout/view_asset_view_mode.xml | 8 +-- 9 files changed, 95 insertions(+), 9 deletions(-) rename common/src/main/res/anim/{asset_mode_out.xml => asset_mode_fade_in.xml} (85%) rename common/src/main/res/anim/{asset_mode_in.xml => asset_mode_fade_out.xml} (85%) create mode 100644 common/src/main/res/anim/asset_mode_slide_bottom_in.xml create mode 100644 common/src/main/res/anim/asset_mode_slide_bottom_out.xml create mode 100644 common/src/main/res/anim/asset_mode_slide_top_in.xml create mode 100644 common/src/main/res/anim/asset_mode_slide_top_out.xml diff --git a/common/src/main/res/anim/asset_mode_out.xml b/common/src/main/res/anim/asset_mode_fade_in.xml similarity index 85% rename from common/src/main/res/anim/asset_mode_out.xml rename to common/src/main/res/anim/asset_mode_fade_in.xml index 320b08d13d..33a1e91d0d 100644 --- a/common/src/main/res/anim/asset_mode_out.xml +++ b/common/src/main/res/anim/asset_mode_fade_in.xml @@ -1,6 +1,5 @@ - - + + + \ No newline at end of file diff --git a/common/src/main/res/anim/asset_mode_slide_bottom_out.xml b/common/src/main/res/anim/asset_mode_slide_bottom_out.xml new file mode 100644 index 0000000000..d6e7826cac --- /dev/null +++ b/common/src/main/res/anim/asset_mode_slide_bottom_out.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/common/src/main/res/anim/asset_mode_slide_top_in.xml b/common/src/main/res/anim/asset_mode_slide_top_in.xml new file mode 100644 index 0000000000..f17339bd58 --- /dev/null +++ b/common/src/main/res/anim/asset_mode_slide_top_in.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/common/src/main/res/anim/asset_mode_slide_top_out.xml b/common/src/main/res/anim/asset_mode_slide_top_out.xml new file mode 100644 index 0000000000..702bd58091 --- /dev/null +++ b/common/src/main/res/anim/asset_mode_slide_top_out.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt index ccae284ee6..2ed55c469a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt @@ -48,6 +48,7 @@ import io.novafoundation.nova.feature_wallet_connect_api.presentation.mapNumberO import kotlinx.coroutines.async import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.launchIn @@ -169,7 +170,7 @@ class BalanceListViewModel( AssetViewMode.NETWORKS -> AssetViewModeModel(R.drawable.ic_asset_view_networks, R.string.asset_view_networks) AssetViewMode.TOKENS -> AssetViewModeModel(R.drawable.ic_asset_view_tokens, R.string.asset_view_tokens) } - } + }.distinctUntilChanged() init { selectedCurrency diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt index b0eb8b1e9e..a41082d482 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt @@ -4,6 +4,9 @@ import android.content.Context import android.util.AttributeSet import android.view.Gravity import android.view.View +import android.view.animation.Animation +import android.view.animation.AnimationUtils +import android.view.animation.AnticipateOvershootInterpolator import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView @@ -23,6 +26,27 @@ class AssetViewModeView @JvmOverloads constructor( override val providedContext: Context = context + private var slideAnimationBottom = true + + private val animationListener = object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation?) { + isClickable = false + } + + override fun onAnimationEnd(animation: Animation?) { + isClickable = true + } + + override fun onAnimationRepeat(animation: Animation?) { + + } + } + + private val slideTopInAnimation = AnimationUtils.loadAnimation(context, R.anim.asset_mode_slide_top_in).applyInterpolator() + private val slideTopOutAnimation = AnimationUtils.loadAnimation(context, R.anim.asset_mode_slide_top_out).applyInterpolator() + private val slideBottomInAnimation = AnimationUtils.loadAnimation(context, R.anim.asset_mode_slide_bottom_in).applyInterpolator() + private val slideBottomOutAnimation = AnimationUtils.loadAnimation(context, R.anim.asset_mode_slide_bottom_out).applyInterpolator() + init { View.inflate(context, R.layout.view_asset_view_mode, this) @@ -41,6 +65,9 @@ class AssetViewModeView @JvmOverloads constructor( textView.setTextColorRes(R.color.text_primary) textView } + + slideTopInAnimation.setAnimationListener(animationListener) + slideBottomInAnimation.setAnimationListener(animationListener) } fun switchTextTo(model: AssetViewModeModel) { @@ -48,9 +75,35 @@ class AssetViewModeView @JvmOverloads constructor( } fun switchTextTo(@DrawableRes iconRes: Int, @StringRes textRes: Int) { + if (!shouldPlayAnimation(textRes)) return + assetViewModeIcon.setImageResource(iconRes) + + assetViewModeText.currentView + + if (slideAnimationBottom) { + assetViewModeText.inAnimation = slideBottomInAnimation + assetViewModeText.outAnimation = slideBottomOutAnimation + } else { + assetViewModeText.inAnimation = slideTopInAnimation + assetViewModeText.outAnimation = slideTopOutAnimation + } + + slideAnimationBottom = !slideAnimationBottom + assetViewModeText.setText(context.getText(textRes)) } + + private fun Animation.applyInterpolator(): Animation { + interpolator = AnticipateOvershootInterpolator(2.0f) + return this + } + + private fun shouldPlayAnimation(@StringRes textRes: Int): Boolean { + val currentTextView = assetViewModeText.currentView as? TextView ?: return true + + return currentTextView.text != context.getString(textRes) + } } -class AssetViewModeModel(@DrawableRes val iconRes: Int, @StringRes val textRes: Int) +data class AssetViewModeModel(@DrawableRes val iconRes: Int, @StringRes val textRes: Int) diff --git a/feature-assets/src/main/res/layout/view_asset_view_mode.xml b/feature-assets/src/main/res/layout/view_asset_view_mode.xml index 598c790f21..fb9fe92c9e 100644 --- a/feature-assets/src/main/res/layout/view_asset_view_mode.xml +++ b/feature-assets/src/main/res/layout/view_asset_view_mode.xml @@ -10,14 +10,12 @@ android:id="@+id/assetViewModeIcon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:inAnimation="@anim/asset_mode_in" - android:outAnimation="@anim/asset_mode_out" /> + android:inAnimation="@anim/asset_mode_fade_in" + android:outAnimation="@anim/asset_mode_fade_out" /> + android:layout_height="wrap_content" /> \ No newline at end of file From 62f0181be92bdc841928e5f63097f645309dffde Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Sun, 20 Oct 2024 14:44:22 +0200 Subject: [PATCH 07/78] Draw expanding animation --- common/build.gradle | 1 + .../nova/common/utils/ListExt.kt | 26 +++ .../nova/common/utils/MapExt.kt | 28 ++++ .../nova/common/utils/ViewExt.kt | 4 + .../expandable/ExpandableAdapter.kt | 9 + .../expandable/ExpandableAnimationExt.kt | 26 +++ .../expandable/ExpandableAnimationSettings.kt | 5 + .../expandable/ExpandableItemAnimator.kt | 143 ++++++++++++++++ .../expandable/ExpandableItemDecoration.kt | 79 +++++++++ .../expandable/ExpandableViewHolder.kt | 8 + .../expandable/animator/ExpandableAnimator.kt | 102 ++++++++++++ .../expandable/items/ExpandableBaseItem.kt | 9 + .../expandable/items/ExpandableChildItem.kt | 6 + .../expandable/items/ExpandableParentItem.kt | 7 + common/src/main/res/values/colors.xml | 1 + .../balance/common/AssetListMixin.kt | 2 +- .../balance/common/AssetTokensDecoration.kt | 155 ++++++++++++++++++ .../balance/common/AssetTokensItemAnimator.kt | 122 ++++++++++++++ .../balance/common/BalanceListAdapter.kt | 11 +- .../balance/common/BalanceListRecyclerView.kt | 28 ++++ .../holders/NetworkAssetGroupViewHolder.kt | 3 +- .../common/holders/NetworkAssetViewHolder.kt | 3 +- .../holders/TokenAssetGroupViewHolder.kt | 4 +- .../common/holders/TokenAssetViewHolder.kt | 3 +- .../balance/list/BalanceListFragment.kt | 23 ++- .../balance/list/model/items/AssetRvItem.kt | 15 +- .../list/model/items/NetworkAssetUi.kt | 2 +- .../list/model/items/NetworkGroupUi.kt | 2 +- .../balance/list/model/items/TokenAssetUi.kt | 2 +- .../balance/list/model/items/TokenGroupUi.kt | 2 +- .../main/res/layout/fragment_balance_list.xml | 2 +- 31 files changed, 813 insertions(+), 20 deletions(-) create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAdapter.kt create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationSettings.kt create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableViewHolder.kt create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableBaseItem.kt create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableChildItem.kt create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableParentItem.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListRecyclerView.kt diff --git a/common/build.gradle b/common/build.gradle index 0a119a8950..a9bff9c7d2 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -93,6 +93,7 @@ dependencies { implementation viewModelKtxDep implementation daggerDep + implementation 'androidx.asynclayoutinflater:asynclayoutinflater:1.0.0' kapt daggerKapt implementation lifecycleDep diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/ListExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/ListExt.kt index 370ceba817..44a4a6f11f 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/ListExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/ListExt.kt @@ -50,3 +50,29 @@ fun List.rangeCheck(fromIndex: Int, toIndex: Int) { toIndex > size -> throw IndexOutOfBoundsException("toIndex ($toIndex) is greater than size ($size).") } } + +fun List.findByStep(fromPosition: Int, step: Int, predicate: (T) -> Boolean): T? { + return findIndexByStep(fromPosition, step, predicate)?.let { get(it) } +} + +fun List.findIndexByStep(fromPosition: Int, step: Int, predicate: (T) -> Boolean): Int? { + if (fromPosition < 0) return null + if (fromPosition >= size) return null + if (step == 0) return null + + var currentPosition = fromPosition + while (currentPosition in 0 until size) { + if (predicate(get(currentPosition))) { + return currentPosition + } + + currentPosition += step + } + + return null +} + +fun Sequence.subList(fromIndex: Int, toIndex: Int): List { + return toList().subList(fromIndex, toIndex) +} + diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/MapExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/MapExt.kt index 9e44175427..72b681b920 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/MapExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/MapExt.kt @@ -8,3 +8,31 @@ inline fun Map.filterValuesIsInstance(): Map { fun mapOfNotNullValues(vararg pairs: Pair): Map { return mapOf(*pairs).filterNotNull() } + +/** + * Groups items Sequentially step by step. Awaits that items is sorted + * Defines a group of elements and puts all subsequent elements in that group until the next group found + * @param keyForEmptyValue - is called when there is no group for item: [Item, Item, Group, Item Item] - for this case will create Group for first two items + */ +fun List.groupSequentially( + isKey: (T) -> Boolean, + keyForEmptyValue: (T) -> T // Generates key if there is no key for value in list +): Map> { + val resultMap = mutableMapOf>() + + var currentValues: MutableList? = null + forEach { + if (isKey(it)) { + currentValues = mutableListOf() + resultMap[it] = currentValues!! + } else { + if (currentValues == null) { + currentValues = mutableListOf() + resultMap[keyForEmptyValue(it)] = currentValues!! + } + currentValues!! += it + } + } + + return resultMap +} diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/ViewExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/ViewExt.kt index 64ca9c9624..76402edeac 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/ViewExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/ViewExt.kt @@ -264,6 +264,10 @@ fun RecyclerView.findFirstVisiblePosition(): Int { return (layoutManager as LinearLayoutManager).findFirstVisibleItemPosition() } +fun RecyclerView.findLastVisiblePosition(): Int { + return (layoutManager as LinearLayoutManager).findLastVisibleItemPosition() +} + fun ScrollView.scrollOnFocusTo(vararg focusableTargets: View) { val listener = View.OnFocusChangeListener { view, hasFocus -> if (hasFocus) { diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAdapter.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAdapter.kt new file mode 100644 index 0000000000..e45135f9c4 --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAdapter.kt @@ -0,0 +1,9 @@ +package io.novafoundation.nova.common.utils.recyclerView.expandable + +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem + +interface ExpandableAdapter { + + fun getItems(): List +} + diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt new file mode 100644 index 0000000000..5aa8437f4d --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt @@ -0,0 +1,26 @@ +package io.novafoundation.nova.common.utils.recyclerView.expandable + +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimationItemState +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem + +fun ExpandableAnimationItemState.flippedFraction(): Float { + return 1f - animationFraction +} + +fun Float.flippedFraction(): Float { + return 1f - this +} + +fun ExpandableAnimationItemState.expandingFraction(): Float { + return when (animationType) { + ExpandableAnimationItemState.Type.EXPANDING -> animationFraction + ExpandableAnimationItemState.Type.COLLAPSING -> flippedFraction() + } +} + +fun ExpandableAdapter.getItemFor(viewHolder: ViewHolder): ExpandableBaseItem? { + if (viewHolder !is ExpandableViewHolder) return null + + return getItems().getOrNull(viewHolder.absoluteAdapterPosition - 1) +} diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationSettings.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationSettings.kt new file mode 100644 index 0000000000..aca4b7a2c5 --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationSettings.kt @@ -0,0 +1,5 @@ +package io.novafoundation.nova.common.utils.recyclerView.expandable + +import android.view.animation.Interpolator + +class ExpandableAnimationSettings(val duration: Long, val interpolator: Interpolator) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt new file mode 100644 index 0000000000..0f9c384d28 --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt @@ -0,0 +1,143 @@ +package io.novafoundation.nova.common.utils.recyclerView.expandable + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import androidx.recyclerview.widget.RecyclerView.ItemAnimator +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import io.novafoundation.nova.common.utils.findIndexByStep +import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator +import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimationItemState +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem + + +class ExpandableItemAnimator( + private val adapter: ExpandableAdapter, + private val settings: ExpandableAnimationSettings, + private val expandableAnimator: ExpandableAnimator +) : ItemAnimator() { + + private var isRunning = false + + private val pendingAnimations = mutableMapOf>() // Item id to ViewHolder + + init { + addDuration = settings.duration + moveDuration = 500 + changeDuration = 500 + } + + override fun animateDisappearance(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo, postLayoutInfo: ItemHolderInfo?): Boolean { + viewHolder.itemView.alpha = 0f + return true + } + + override fun animateAppearance(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo?, postLayoutInfo: ItemHolderInfo): Boolean { + val item = adapter.getItemFor(viewHolder) + + if (item !is ExpandableChildItem) return false + + + val (parentPosition, parentItem) = findParentFor(viewHolder) ?: return false + + viewHolder.itemView.alpha = 0f + viewHolder.itemView.scaleX = 0.7f + viewHolder.itemView.scaleY = 0.7f + + val position = viewHolder.absoluteAdapterPosition - parentPosition + //viewHolder.itemView.translationY = 50f - viewHolder.itemView.height / 2f * 0.7f * position + val itemKey = parentItem.toKey() + val currentViewHolders = pendingAnimations[itemKey] ?: emptyList() + pendingAnimations[itemKey] = currentViewHolders + listOf(viewHolder) + return true + } + + override fun animatePersistence(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo, postLayoutInfo: ItemHolderInfo): Boolean { + return false + } + + override fun animateChange( + oldHolder: ViewHolder, + newHolder: ViewHolder, + preLayoutInfo: ItemHolderInfo, + postLayoutInfo: ItemHolderInfo + ): Boolean { + return true + } + + override fun runPendingAnimations() { + val parentItems = pendingAnimations.keys.toList() + val animatingViewHolders = pendingAnimations.flatMap { (_, viewHolders) -> viewHolders } + pendingAnimations.clear() + val adder = Runnable { + for (holder in animatingViewHolders) { + animateAddImpl(holder) + } + } + + parentItems.forEach { expandableAnimator.animateItemToState(it.item, ExpandableAnimationItemState.Type.EXPANDING) } + adder.run() + } + + fun animateAddImpl(holder: ViewHolder) { + val view = holder.itemView + val animation = view.animate() + animation.alpha(1f) + .scaleX(1f) + .scaleY(1f) + .setDuration(settings.duration) + .translationY(0f) + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationStart(animator: Animator) { + isRunning = true + } + + override fun onAnimationCancel(animator: Animator) { + isRunning = false + view.alpha = 1f + view.scaleX = 1f + } + + override fun onAnimationEnd(animator: Animator) { + isRunning = false + animation.setListener(null) + } + }).start() + } + + override fun endAnimation(viewHolder: ViewHolder) { + // Nothing to do + } + + override fun endAnimations() { + expandableAnimator.cancelAnimations() + } + + override fun isRunning(): Boolean { + return isRunning + } + + private fun findParentFor(viewHolder: ViewHolder): Pair? { + val items = adapter.getItems() + val adapterPosition = viewHolder.absoluteAdapterPosition + val groupPosition = items.findIndexByStep(fromPosition = adapterPosition, -1) { it is ExpandableParentItem } ?: return null + + return groupPosition to items[groupPosition] as ExpandableParentItem + } +} + +private class ItemKey(val item: ExpandableParentItem) { + + override fun equals(other: Any?): Boolean { + if (other !is ItemKey) return false + return item.getId() == other.item.getId() + } + + override fun hashCode(): Int { + return item.hashCode() + } +} + +private fun ExpandableParentItem.toKey(): ItemKey { + return ItemKey(this) +} diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt new file mode 100644 index 0000000000..714ed8a6ef --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt @@ -0,0 +1,79 @@ +package io.novafoundation.nova.common.utils.recyclerView.expandable + +import android.graphics.Canvas +import android.graphics.Rect +import android.view.View +import androidx.core.view.children +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import io.novafoundation.nova.common.utils.findByStep +import io.novafoundation.nova.common.utils.groupSequentially +import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator +import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimationItemState +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem + +private class ItemWithViewHolder(val position: Int, val item: ExpandableBaseItem, val viewHolder: RecyclerView.ViewHolder?) + +interface GroupAnimationDecoration { + fun onDraw( + canvas: Canvas, + expandableItemState: ExpandableAnimationItemState, + parent: RecyclerView, + groupViewHolder: ViewHolder, + items: List + ) +} + +abstract class ExpandableItemDecoration( + private val adapter: ExpandableAdapter, + private val animator: ExpandableAnimator +) : RecyclerView.ItemDecoration() { + + abstract fun onDrawGroup( + canvas: Canvas, + animationState: ExpandableAnimationItemState, + recyclerView: RecyclerView, + parent: ViewHolder?, + children: List + ) + + override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + + } + + override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) { + val items = try { + getParentAndChildren(parent) + } catch (e: Exception) { + emptyMap() + } + + for ((parentItem, children) in items) { + val animationState = animator.getStateForPosition(parentItem.position) ?: continue + val childViewHolders = children.mapNotNull { it.viewHolder } + onDrawGroup(canvas, animationState, parent, parentItem.viewHolder, childViewHolders) + } + } + + private fun getParentAndChildren(parent: RecyclerView): Map> { + return parent.children.toList() + .mapNotNull { + val position = parent.getChildAdapterPosition(it) - 1 + val viewHolder = parent.getChildViewHolder(it) + val item = adapter.getItemFor(viewHolder) ?: return@mapNotNull null + ItemWithViewHolder(position, item, viewHolder) + } + .sortedBy { it.position } + .groupSequentially( + isKey = { it.item is ExpandableParentItem }, + keyForEmptyValue = { getParentForPosition(it.position) } + ) + } + + private fun getParentForPosition(position: Int): ItemWithViewHolder { + val item = adapter.getItems().findByStep(fromPosition = position, -1) { it is ExpandableParentItem } + + return ItemWithViewHolder(position, item as ExpandableParentItem, null) + } +} diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableViewHolder.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableViewHolder.kt new file mode 100644 index 0000000000..06c6fa6b3c --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableViewHolder.kt @@ -0,0 +1,8 @@ +package io.novafoundation.nova.common.utils.recyclerView.expandable + +/** + * The view holder that may show ExpandingItem's + * It's used to check the type of viewHolder in [ExpandableItemDecoration] + */ +interface ExpandableViewHolder + diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt new file mode 100644 index 0000000000..1f2547d7a3 --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt @@ -0,0 +1,102 @@ +package io.novafoundation.nova.common.utils.recyclerView.expandable.animator + +import android.animation.Animator +import android.animation.ValueAnimator +import androidx.core.animation.addListener +import androidx.recyclerview.widget.RecyclerView +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAdapter +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAnimationSettings +import io.novafoundation.nova.common.utils.recyclerView.expandable.flippedFraction +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem + +/** + * Where animationFraction = 0f - fully collapsed and animationFraction = 1f - fully expanded + */ +class ExpandableAnimationItemState(val animationType: Type, animationFraction: Float) { + + var animationFraction: Float = animationFraction + internal set(value) { + field = value.coerceIn(0f, 1f) + } + + enum class Type { + EXPANDING, COLLAPSING + } +} + +private class RunningAnimation(val currentState: ExpandableAnimationItemState, val animator: Animator) + +class ExpandableAnimator( + private val recyclerView: RecyclerView, + private val animationSettings: ExpandableAnimationSettings, + private val expandableAdapter: ExpandableAdapter +) { + + // It contains only items that is animating right now + private val runningAnimations = mutableMapOf() + + fun getStateForPosition(position: Int): ExpandableAnimationItemState? { + val items = expandableAdapter.getItems() + val item = items[position] + if (item !is ExpandableParentItem) return null + + return runningAnimations[item.getId()]?.currentState ?: getExpandableItemState(position, items) + } + + fun animateItemToState(item: ExpandableParentItem, type: ExpandableAnimationItemState.Type) { + val existingSettings = runningAnimations[item.getId()] + + // No need to run animation if animation state is running and current type is the same + if (existingSettings == null) { + val state = ExpandableAnimationItemState(type, 0f) + runAnimationFor(item, state) + } else { + // No need to update animation state if it's the same and already running + if (existingSettings.currentState.animationType == type) { + return + } + + // Toggle animation state and flipping fraction to continue the animation but to another side + val state = ExpandableAnimationItemState(type, existingSettings.currentState.flippedFraction()) + runAnimationFor(item, state) + } + } + + private fun runAnimationFor(item: ExpandableParentItem, state: ExpandableAnimationItemState) { + runningAnimations[item.getId()]?.animator?.cancel() // Cancel previous animation if it's exist + + val animator = ValueAnimator.ofFloat(state.animationFraction, 1f) + .setDuration(animationSettings.duration) + + animator.interpolator = animationSettings.interpolator + animator.addUpdateListener { + state.animationFraction = it.animatedValue as Float + recyclerView.invalidate() + } // Invalidate recycler view to trigger onDraw in Item Decoration + animator.addListener( + onEnd = { runningAnimations.remove(item.getId()) }, + onCancel = { runningAnimations.remove(item.getId()) } + ) + + runningAnimations[item.getId()] = RunningAnimation(state, animator) + animator.start() + } + + fun cancelAnimations() { + runningAnimations.values + .toList() // Copy list to avoid ConcurrentModificationException + .forEach { it.animator.cancel() } + } + + private fun getExpandableItemState(position: Int, items: List): ExpandableAnimationItemState { + val nextItem = items.getOrNull(position + 1) + + // If next item is not a parent item it means current item is fully expanded + return if (nextItem == null || nextItem !is ExpandableParentItem) { + ExpandableAnimationItemState(ExpandableAnimationItemState.Type.EXPANDING, 1f) + } else { + ExpandableAnimationItemState(ExpandableAnimationItemState.Type.COLLAPSING, 1f) + } + } +} diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableBaseItem.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableBaseItem.kt new file mode 100644 index 0000000000..b49cdd6578 --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableBaseItem.kt @@ -0,0 +1,9 @@ +package io.novafoundation.nova.common.utils.recyclerView.expandable.items + +/** + * The item that may show ExpandingItem's + */ +interface ExpandableBaseItem { + fun getId(): String +} + diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableChildItem.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableChildItem.kt new file mode 100644 index 0000000000..ac55e73737 --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableChildItem.kt @@ -0,0 +1,6 @@ +package io.novafoundation.nova.common.utils.recyclerView.expandable.items + +/** + * The item that may be shown or hidden From ExpandableItem + */ +interface ExpandableChildItem : ExpandableBaseItem diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableParentItem.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableParentItem.kt new file mode 100644 index 0000000000..e0b38ff0e8 --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableParentItem.kt @@ -0,0 +1,7 @@ +package io.novafoundation.nova.common.utils.recyclerView.expandable.items + +/** + * The item that may show ExpandingItem's + */ +interface ExpandableParentItem : ExpandableBaseItem + diff --git a/common/src/main/res/values/colors.xml b/common/src/main/res/values/colors.xml index 65457f8835..7bcdb91c89 100644 --- a/common/src/main/res/values/colors.xml +++ b/common/src/main/res/values/colors.xml @@ -61,6 +61,7 @@ #08090E #181920 #1A999EC7 + #3D999EC7 #5205081C #291F78FF diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index bf235f7a33..9f5f0a94df 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -99,7 +99,7 @@ class RealAssetListMixin( } override fun expandToken(tokenGroupUi: TokenGroupUi) { - expandedTokenIdsFlow.updateValue { it.toggle(tokenGroupUi.id) } + expandedTokenIdsFlow.updateValue { it.toggle(tokenGroupUi.itemId) } } private fun filterExpandedItems(entry: Map.Entry>, expandedTokens: Set): List { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt new file mode 100644 index 0000000000..6b72d2771e --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt @@ -0,0 +1,155 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common + +import android.animation.ArgbEvaluator +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Path +import android.graphics.Rect +import android.graphics.RectF +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import io.novafoundation.nova.common.utils.dp +import io.novafoundation.nova.common.utils.dpF +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAdapter +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableItemDecoration +import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimationItemState +import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator +import io.novafoundation.nova.common.utils.recyclerView.expandable.expandingFraction +import io.novafoundation.nova.common.utils.recyclerView.expandable.flippedFraction +import io.novafoundation.nova.feature_assets.R +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetGroupViewHolder + +class AssetTokensDecoration( + private val context: Context, + adapter: ExpandableAdapter, + animator: ExpandableAnimator +) : ExpandableItemDecoration( + adapter, + animator +) { + private val argbEvaluator = ArgbEvaluator() + + private val childrenBlockCollapsedHorizontalMargin = 16.dp(context) + private val childrenBlockCollapsedHeight = 4.dp(context) + + private val blockRadiusCollapsed = 4.dpF(context) + private val blockRadiusExpanded = 12.dpF(context) + private val blockRadiusDelta = blockRadiusExpanded - blockRadiusCollapsed + + private val blockColor = context.getColor(R.color.block_background) + private val hidedBlockColor = context.getColor(R.color.hided_networks_block_background) + private val transparentColor = Color.TRANSPARENT + private val dividerColor = context.getColor(R.color.divider) + + private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.FILL + } + + private val linePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.STROKE + } + + private var drawingPath = Path() + + override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + val viewHolder = parent.getChildViewHolder(view) + + if (viewHolder is TokenAssetGroupViewHolder) { + outRect.set(0, 12.dp(context), 0, 0) + return + } + } + + override fun onDrawGroup( + canvas: Canvas, + animationState: ExpandableAnimationItemState, + recyclerView: RecyclerView, + parent: RecyclerView.ViewHolder?, + children: List + ) { + val expandingFraction = animationState.expandingFraction() + val flippedExpandingFraction = expandingFraction.flippedFraction() + + val parentBounds = parentBounds(parent) + if (parentBounds != null) { + drawParentBlock(flippedExpandingFraction, parentBounds, canvas, expandingFraction) + } + + val childrenBlockBounds = getChildrenBlockBounds(animationState, recyclerView, parent, children) + drawChildrenBlock(expandingFraction, childrenBlockBounds, canvas) + } + + private fun drawChildrenBlock(expandingFraction: Float, childrenBlockBounds: RectF, canvas: Canvas) { + val animatedBlockRadius = blockRadiusDelta * expandingFraction + childrenBlockBounds.toPath(drawingPath, topRadius = 0f, bottomRadius = blockRadiusCollapsed + animatedBlockRadius * expandingFraction) + paint.color = argbEvaluator.evaluate(expandingFraction, hidedBlockColor, blockColor) as Int + canvas.drawPath(drawingPath, paint) + } + + private fun drawParentBlock( + flippedExpandingFraction: Float, + parentBounds: RectF, + canvas: Canvas, + expandingFraction: Float + ) { + val path = Path() + val bottomRadius = blockRadiusExpanded * flippedExpandingFraction + parentBounds.toPath(path, topRadius = blockRadiusExpanded, bottomRadius = bottomRadius) + paint.color = blockColor + canvas.drawPath(path, paint) + + drawParentDivider(expandingFraction, bottomRadius, canvas, parentBounds) + } + + private fun drawParentDivider( + expandingFraction: Float, + dividerMargin: Float, + canvas: Canvas, + parentBounds: RectF + ) { + linePaint.color = argbEvaluator.evaluate(expandingFraction, transparentColor, dividerColor) as Int + canvas.drawLine(parentBounds.left + dividerMargin, parentBounds.bottom, parentBounds.right - dividerMargin, parentBounds.bottom, linePaint) + } + + + private fun parentBounds(parent: RecyclerView.ViewHolder?): RectF? { + if (parent == null) return null + + return parent.itemView.let { RectF(it.left.toFloat(), it.top.toFloat(), it.right.toFloat(), it.bottom.toFloat()) } + } + + private fun getChildrenBlockBounds( + animationState: ExpandableAnimationItemState, + recyclerView: RecyclerView, + parent: RecyclerView.ViewHolder?, + children: List + ): RectF { + val lastChild = children.lastOrNull() + + val top = parent?.itemView?.bottom ?: recyclerView.top + val bottom = lastChild?.itemView?.bottom ?: top // In case if last child is null -> content is empty and we will draw the empty and collapsed block + val left = parent?.itemView?.left ?: lastChild?.itemView?.left ?: recyclerView.left + val right = parent?.itemView?.right ?: lastChild?.itemView?.right ?: recyclerView.right + + val expandingFraction = animationState.expandingFraction() + val flippedExpandingFraction = expandingFraction.flippedFraction() + val heightDelta = (bottom - top) + return RectF( + left + childrenBlockCollapsedHorizontalMargin * flippedExpandingFraction, + top.toFloat(), + right - childrenBlockCollapsedHorizontalMargin * flippedExpandingFraction, + top + childrenBlockCollapsedHeight + heightDelta * expandingFraction + ) + } + + private fun RectF.toPath(path: Path, topRadius: Float, bottomRadius: Float) { + path.reset() + path.addRoundRect( + this, + floatArrayOf(topRadius, topRadius, topRadius, topRadius, bottomRadius, bottomRadius, bottomRadius, bottomRadius), + Path.Direction.CW + ) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt new file mode 100644 index 0000000000..0e9a4077aa --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt @@ -0,0 +1,122 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ItemAnimator +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import io.novafoundation.nova.common.utils.findIndexByStep +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetViewHolder +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi + +class AssetTokensItemAnimator( + private val adapter: BalanceListAdapter, + private val decoration: AssetTokensDecoration, + private val recyclerView: BalanceListRecyclerView +) : ItemAnimator() { + + private var isRunning = false + + private val pendingAnimations = mutableListOf() + + init { + addDuration = 500 + moveDuration = 500 + changeDuration = 500 + } + + override fun onAnimationFinished(viewHolder: ViewHolder) { + recyclerView.invalidate() + } + + + override fun animateDisappearance(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo, postLayoutInfo: ItemHolderInfo?): Boolean { + viewHolder.itemView.alpha = 0f + return true + } + + override fun animateAppearance(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo?, postLayoutInfo: ItemHolderInfo): Boolean { + if (viewHolder !is TokenAssetViewHolder) return false + viewHolder.itemView.alpha = 0f + viewHolder.itemView.scaleX = 0.7f + viewHolder.itemView.scaleY = 0.7f + + val adapterPosition = viewHolder.absoluteAdapterPosition + val groupPosition = adapter.currentList.findIndexByStep(fromPosition = adapterPosition, -1) { it is TokenGroupUi } ?: return false + val position = viewHolder.absoluteAdapterPosition - groupPosition + viewHolder.itemView.translationY = 50f - viewHolder.itemView.height / 2f * 0.7f * position + pendingAnimations.add(viewHolder) + return true + } + + override fun animatePersistence(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo, postLayoutInfo: ItemHolderInfo): Boolean { + return false + } + + override fun animateChange( + oldHolder: ViewHolder, + newHolder: ViewHolder, + preLayoutInfo: ItemHolderInfo, + postLayoutInfo: ItemHolderInfo + ): Boolean { + return true + } + + override fun runPendingAnimations() { + val additions = ArrayList() + additions.addAll(pendingAnimations) + pendingAnimations.clear() + val adder = Runnable { + for (holder in additions) { + animateAddImpl(holder) + } + additions.clear() + } + + adder.run() + } + + fun animateAddImpl(holder: ViewHolder) { + val view = holder.itemView + val animation = view.animate() + animation.alpha(1f) + .scaleX(1f) + .scaleY(1f) + .setDuration(500) + .translationY(0f) + .setUpdateListener { + recyclerView.invalidate() + } + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationStart(animator: Animator) { + recyclerView.invalidate() + isRunning = true + } + + override fun onAnimationCancel(animator: Animator) { + recyclerView.invalidate() + isRunning = false + view.alpha = 1f + view.scaleX = 1f + } + + override fun onAnimationEnd(animator: Animator) { + recyclerView.invalidate() + isRunning = false + animation.setListener(null) + } + }).start() + } + + override fun endAnimation(item: ViewHolder) { + + } + + override fun endAnimations() { + } + + override fun isRunning(): Boolean { + return isRunning + } +} + diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt index b17ae1c29a..bb9707cc3a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt @@ -9,6 +9,9 @@ import coil.ImageLoader import io.novafoundation.nova.common.list.PayloadGenerator import io.novafoundation.nova.common.list.resolvePayload import io.novafoundation.nova.common.utils.inflateChild +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAdapter +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableViewHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetGroupViewHolder import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetViewHolder @@ -37,7 +40,7 @@ const val TYPE_TOKEN_ASSET = 3 class BalanceListAdapter( private val imageLoader: ImageLoader, private val itemHandler: ItemAssetHandler, -) : ListAdapter(DiffCallback) { +) : ListAdapter(DiffCallback), ExpandableAdapter { interface ItemAssetHandler { fun assetClicked(asset: AssetModel) @@ -111,12 +114,16 @@ class BalanceListAdapter( else -> error("Unknown item type") } } + + override fun getItems(): List { + return currentList + } } private object DiffCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: BalanceListRvItem, newItem: BalanceListRvItem): Boolean { - return oldItem.id == newItem.id + return oldItem.itemId == newItem.itemId } @SuppressLint("DiffUtilEquals") diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListRecyclerView.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListRecyclerView.kt new file mode 100644 index 0000000000..979dc24215 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListRecyclerView.kt @@ -0,0 +1,28 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common + +import android.content.Context +import android.graphics.Canvas +import android.util.AttributeSet +import androidx.recyclerview.widget.RecyclerView + +class BalanceListRecyclerView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyle: Int = 0, +) : RecyclerView(context, attrs, defStyle) { + + private var drawingAvailable = true + + init { + setWillNotDraw(false) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + if (drawingAvailable) { + //drawing.draw(canvas, 0f, 0f) + } + } + +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt index 352490f828..5457ce674f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt @@ -2,13 +2,14 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableViewHolder import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkGroupUi import kotlinx.android.synthetic.main.item_network_asset_group.view.itemAssetGroupBalance import kotlinx.android.synthetic.main.item_network_asset_group.view.itemAssetGroupChain class NetworkAssetGroupViewHolder( containerView: View, -) : GroupedListHolder(containerView) { +) : GroupedListHolder(containerView), ExpandableViewHolder { fun bind(assetGroup: NetworkGroupUi) = with(containerView) { itemAssetGroupChain.setChain(assetGroup.chainUi) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt index 36e8d75d6d..1444928355 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableViewHolder import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter @@ -18,7 +19,7 @@ import kotlinx.android.synthetic.main.item_network_asset.view.itemAssetToken class NetworkAssetViewHolder( containerView: View, private val imageLoader: ImageLoader, -) : GroupedListHolder(containerView) { +) : GroupedListHolder(containerView), ExpandableViewHolder { fun bind(networkAsset: NetworkAssetUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { val asset = networkAsset.asset diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt index 13703413d8..b24a66df62 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableViewHolder import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter @@ -14,10 +15,11 @@ import kotlinx.android.synthetic.main.item_token_asset_group.view.itemAssetToken import kotlinx.android.synthetic.main.item_token_asset_group.view.itemAssetTokenGroupToken import kotlinx.android.synthetic.main.item_token_asset_group.view.itemTokenGroupAssetImage + class TokenAssetGroupViewHolder( containerView: View, private val imageLoader: ImageLoader, -) : GroupedListHolder(containerView) { +) : GroupedListHolder(containerView), ExpandableViewHolder { fun bind(tokenGroup: TokenGroupUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { itemTokenGroupAssetImage.loadTokenIcon(tokenGroup.tokenIcon, imageLoader) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt index 86e4dd9b9e..b6c6c6027f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableViewHolder import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi @@ -17,7 +18,7 @@ import kotlinx.android.synthetic.main.item_token_asset.view.itemTokenAssetPriceA class TokenAssetViewHolder( containerView: View, private val imageLoader: ImageLoader, -) : GroupedListHolder(containerView) { +) : GroupedListHolder(containerView), ExpandableViewHolder { fun bind(tokenAsset: TokenAssetUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { val asset = tokenAsset.asset diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index ae91f1844f..9897a501a9 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -4,19 +4,24 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.animation.AccelerateDecelerateInterpolator import androidx.recyclerview.widget.ConcatAdapter import coil.ImageLoader import dev.chrisbanes.insetter.applyInsetter import io.novafoundation.nova.common.base.BaseFragment import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.hideKeyboard +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAnimationSettings +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableItemAnimator +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableItemDecoration +import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.BalanceBreakdownBottomSheet -import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetGroupingDecoration +import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensDecoration +import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensItemAnimator import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter -import io.novafoundation.nova.feature_assets.presentation.balance.common.applyDefaultTo import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetsHeaderAdapter import io.novafoundation.nova.feature_assets.presentation.model.AssetModel @@ -66,10 +71,20 @@ class BalanceListFragment : balanceListAssets.setHasFixedSize(true) balanceListAssets.adapter = adapter - AssetGroupingDecoration.applyDefaultTo(balanceListAssets, assetsAdapter) + //AssetGroupingDecoration.applyDefaultTo(balanceListAssets, assetsAdapter) // modification animations only harm here - balanceListAssets.itemAnimator = null + //val decoration = AssetTokensDecoration(requireContext(), assetsAdapter) + //balanceListAssets.addItemDecoration(decoration) + //balanceListAssets.itemAnimator = AssetTokensItemAnimator(assetsAdapter, decoration, balanceListAssets) + + val settings = ExpandableAnimationSettings(5000, AccelerateDecelerateInterpolator()) + val animator = ExpandableAnimator(balanceListAssets, settings, assetsAdapter) + val decoration = AssetTokensDecoration(requireContext(), assetsAdapter, animator) + val itemAnimator = ExpandableItemAnimator(assetsAdapter, settings, animator) + + balanceListAssets.addItemDecoration(decoration) + balanceListAssets.itemAnimator = itemAnimator walletContainer.setOnRefreshListener { viewModel.fullSync() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt index 4926ab6559..9a72281e17 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt @@ -1,13 +1,20 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem import io.novafoundation.nova.feature_assets.presentation.model.AssetModel -interface BalanceListRvItem { - val id: String +interface BalanceListRvItem : ExpandableBaseItem { + val itemId: String + + override fun getId(): String { + return itemId + } } -interface AssetGroupRvItem : BalanceListRvItem +interface AssetGroupRvItem : BalanceListRvItem, ExpandableParentItem -interface AssetRvItem : BalanceListRvItem { +interface AssetRvItem : BalanceListRvItem, ExpandableChildItem { val asset: AssetModel } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt index 9428662690..9681dec323 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt @@ -4,5 +4,5 @@ import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.runtime.ext.fullId data class NetworkAssetUi(override val asset: AssetModel) : AssetRvItem { - override val id: String = asset.token.configuration.fullId.toString() + override val itemId: String = asset.token.configuration.fullId.toString() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkGroupUi.kt index 1278e1bb4d..6576e6246c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkGroupUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkGroupUi.kt @@ -7,5 +7,5 @@ data class NetworkGroupUi( val groupBalanceFiat: String ) : AssetGroupRvItem { - override val id: String = chainUi.id + override val itemId: String = chainUi.id } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt index 1fcaab65b9..9794524a20 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt @@ -6,5 +6,5 @@ import io.novafoundation.nova.runtime.ext.fullId data class TokenAssetUi(override val asset: AssetModel, val chain: ChainUi) : AssetRvItem { - override val id: String = asset.token.configuration.fullId.toString() + override val itemId: String = asset.token.configuration.fullId.toString() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt index 5495708178..7ca9bfb5be 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt @@ -11,5 +11,5 @@ data class TokenGroupUi( val tokenSymbol: String, val balance: AmountModel ) : AssetGroupRvItem { - override val id: String = tokenSymbol + override val itemId: String = tokenSymbol } diff --git a/feature-assets/src/main/res/layout/fragment_balance_list.xml b/feature-assets/src/main/res/layout/fragment_balance_list.xml index ef69f89765..9440c7c74f 100644 --- a/feature-assets/src/main/res/layout/fragment_balance_list.xml +++ b/feature-assets/src/main/res/layout/fragment_balance_list.xml @@ -7,7 +7,7 @@ android:layout_height="match_parent" android:background="@drawable/drawable_background_image"> - Date: Mon, 21 Oct 2024 14:18:24 +0200 Subject: [PATCH 08/78] Expanding/Collapsing animation --- .../expandable/ExpandableAnimationExt.kt | 2 +- .../expandable/ExpandableItemAnimator.kt | 227 +++++++++++++----- .../expandable/ExpandableItemDecoration.kt | 73 +++--- .../expandable/ExpandableParentViewHolder.kt | 22 ++ .../expandable/ExpandableViewHolder.kt | 8 - .../expandable/items/ExpandableChildItem.kt | 5 +- .../balance/common/AssetTokensDecoration.kt | 51 +++- .../balance/common/BalanceListAdapter.kt | 1 - .../holders/NetworkAssetGroupViewHolder.kt | 4 +- .../common/holders/NetworkAssetViewHolder.kt | 6 +- .../holders/TokenAssetGroupViewHolder.kt | 9 +- .../common/holders/TokenAssetViewHolder.kt | 10 +- .../common/mappers/NetworkAssetMappers.kt | 7 +- .../common/mappers/TokenAssetMappers.kt | 7 +- .../balance/list/BalanceListFragment.kt | 2 +- .../list/model/items/NetworkAssetUi.kt | 2 +- .../balance/list/model/items/TokenAssetUi.kt | 2 +- 17 files changed, 310 insertions(+), 128 deletions(-) create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableParentViewHolder.kt delete mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableViewHolder.kt diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt index 5aa8437f4d..f30c6fd499 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt @@ -20,7 +20,7 @@ fun ExpandableAnimationItemState.expandingFraction(): Float { } fun ExpandableAdapter.getItemFor(viewHolder: ViewHolder): ExpandableBaseItem? { - if (viewHolder !is ExpandableViewHolder) return null + if (viewHolder !is ExpandableBaseViewHolder<*>) return null return getItems().getOrNull(viewHolder.absoluteAdapterPosition - 1) } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt index 0f9c384d28..0978e9a0f3 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt @@ -2,12 +2,10 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable import android.animation.Animator import android.animation.AnimatorListenerAdapter -import androidx.recyclerview.widget.RecyclerView.ItemAnimator import androidx.recyclerview.widget.RecyclerView.ViewHolder -import io.novafoundation.nova.common.utils.findIndexByStep -import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator +import androidx.recyclerview.widget.SimpleItemAnimator import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimationItemState -import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem +import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem @@ -15,68 +13,118 @@ class ExpandableItemAnimator( private val adapter: ExpandableAdapter, private val settings: ExpandableAnimationSettings, private val expandableAnimator: ExpandableAnimator -) : ItemAnimator() { +) : SimpleItemAnimator() { - private var isRunning = false + private val addAnimations = mutableMapOf>() // Item id to ViewHolder + private val removeAnimations = mutableMapOf>() // Item id to ViewHolder + private val moveAnimations = mutableListOf() // Item id to ViewHolder - private val pendingAnimations = mutableMapOf>() // Item id to ViewHolder + private val pendingAddAnimations = mutableSetOf() // Item id to ViewHolder + private val pendingRemoveAnimations = mutableSetOf() // Item id to ViewHolder + private val pendingMoveAnimations = mutableSetOf() // Item id to ViewHolder init { addDuration = settings.duration - moveDuration = 500 - changeDuration = 500 + removeDuration = settings.duration + moveDuration = settings.duration + + supportsChangeAnimations = false } - override fun animateDisappearance(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo, postLayoutInfo: ItemHolderInfo?): Boolean { - viewHolder.itemView.alpha = 0f + override fun animateAdd(holder: ViewHolder): Boolean { + if (holder !is ExpandableChildViewHolder) return false + val item = holder.expandableItem ?: return false + + val parentItem = adapter.getItems().firstOrNull { it.getId() == item.groupId } as? ExpandableParentItem ?: return false + + if (pendingRemoveAnimations.contains(holder)) { + holder.itemView.animate().cancel() + pendingRemoveAnimations.remove(holder) + } else { + holder.itemView.alpha = 0f + holder.itemView.scaleX = 0.95f + holder.itemView.scaleY = 0.95f + } + + //val position = viewHolder.absoluteAdapterPosition - parentPosition + //viewHolder.itemView.translationY = 50f - viewHolder.itemView.height / 2f * 0.7f * position + val itemKey = parentItem.toKey() + val currentViewHolders = addAnimations[itemKey] ?: emptyList() + addAnimations[itemKey] = currentViewHolders + listOf(holder) return true } - override fun animateAppearance(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo?, postLayoutInfo: ItemHolderInfo): Boolean { - val item = adapter.getItemFor(viewHolder) + override fun animateRemove(holder: ViewHolder): Boolean { + if (holder !is ExpandableChildViewHolder) return false + val item = holder.expandableItem ?: return false - if (item !is ExpandableChildItem) return false + val parentItem = adapter.getItems().firstOrNull { it.getId() == item.groupId } as? ExpandableParentItem ?: return false + if (pendingAddAnimations.contains(holder)) { + holder.itemView.animate().cancel() + pendingAddAnimations.remove(holder) + } else { + holder.itemView.alpha = 1f + holder.itemView.scaleX = 1f + holder.itemView.scaleY = 1f + holder.itemView.translationY = 0f + } - val (parentPosition, parentItem) = findParentFor(viewHolder) ?: return false + val itemKey = parentItem.toKey() + val currentViewHolders = removeAnimations[itemKey] ?: emptyList() + removeAnimations[itemKey] = currentViewHolders + listOf(holder) + return true + } - viewHolder.itemView.alpha = 0f - viewHolder.itemView.scaleX = 0.7f - viewHolder.itemView.scaleY = 0.7f + override fun animateMove(holder: ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int): Boolean { + if (pendingMoveAnimations.contains(holder)) { + //holder.itemView.animate().cancel() + //pendingMoveAnimations.remove(holder) + } else { + val yDelta = toY - fromY + holder.itemView.translationY = -yDelta.toFloat() + } - val position = viewHolder.absoluteAdapterPosition - parentPosition - //viewHolder.itemView.translationY = 50f - viewHolder.itemView.height / 2f * 0.7f * position - val itemKey = parentItem.toKey() - val currentViewHolders = pendingAnimations[itemKey] ?: emptyList() - pendingAnimations[itemKey] = currentViewHolders + listOf(viewHolder) + val yDelta = toY - fromY + holder.itemView.translationY = -yDelta.toFloat() + moveAnimations.add(holder) return true } - override fun animatePersistence(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo, postLayoutInfo: ItemHolderInfo): Boolean { + override fun animateChange(oldHolder: ViewHolder?, newHolder: ViewHolder?, fromLeft: Int, fromTop: Int, toLeft: Int, toTop: Int): Boolean { return false } - override fun animateChange( - oldHolder: ViewHolder, - newHolder: ViewHolder, - preLayoutInfo: ItemHolderInfo, - postLayoutInfo: ItemHolderInfo - ): Boolean { - return true + override fun runPendingAnimations() { + runAnimationFor(addAnimations, pendingAddAnimations, ExpandableAnimationItemState.Type.EXPANDING) { animateAddImpl(it) } + runAnimationFor(removeAnimations, pendingRemoveAnimations, ExpandableAnimationItemState.Type.COLLAPSING) { animateRemoveImpl(it) } + + val animatingViewHolders = moveAnimations.toList() + moveAnimations.clear() + + for (holder in animatingViewHolders) { + animateMoveImpl(holder) + } + + pendingMoveAnimations.addAll(animatingViewHolders) } - override fun runPendingAnimations() { - val parentItems = pendingAnimations.keys.toList() - val animatingViewHolders = pendingAnimations.flatMap { (_, viewHolders) -> viewHolders } - pendingAnimations.clear() - val adder = Runnable { - for (holder in animatingViewHolders) { - animateAddImpl(holder) - } + private fun runAnimationFor( + animationGroup: MutableMap>, + pendingAnimations: MutableSet, + toState: ExpandableAnimationItemState.Type, + runAnimation: (ViewHolder) -> Unit + ) { + val parentItems = animationGroup.keys.toList() + val animatingViewHolders = animationGroup.flatMap { (_, viewHolders) -> viewHolders } + animationGroup.clear() + + parentItems.forEach { expandableAnimator.animateItemToState(it.item, toState) } + for (holder in animatingViewHolders) { + runAnimation(holder) } - parentItems.forEach { expandableAnimator.animateItemToState(it.item, ExpandableAnimationItemState.Type.EXPANDING) } - adder.run() + pendingAnimations.addAll(animatingViewHolders) } fun animateAddImpl(holder: ViewHolder) { @@ -86,43 +134,108 @@ class ExpandableItemAnimator( .scaleX(1f) .scaleY(1f) .setDuration(settings.duration) - .translationY(0f) .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationStart(animator: Animator) { - isRunning = true - } + override fun onAnimationStart(animator: Animator) {} override fun onAnimationCancel(animator: Animator) { - isRunning = false + dispatchAnimationFinished(holder) + pendingAddAnimations.remove(holder) view.alpha = 1f view.scaleX = 1f } override fun onAnimationEnd(animator: Animator) { - isRunning = false + dispatchAnimationFinished(holder) + pendingAddAnimations.remove(holder) + animation.setListener(null) + } + }).start() + } + + fun animateRemoveImpl(holder: ViewHolder) { + val view = holder.itemView + val animation = view.animate() + animation.alpha(0f) + .scaleX(0.95f) + .scaleY(0.95f) + .setDuration(settings.duration) + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationStart(animator: Animator) {} + + override fun onAnimationCancel(animator: Animator) { + dispatchAnimationFinished(holder) + pendingRemoveAnimations.remove(holder) + view.alpha = 0f + view.scaleX = 0.95f + } + + override fun onAnimationEnd(animator: Animator) { + dispatchAnimationFinished(holder) + pendingRemoveAnimations.remove(holder) + animation.setListener(null) + } + }).start() + } + + fun animateMoveImpl(holder: ViewHolder) { + val view = holder.itemView + val animation = view.animate() + animation.translationY(0f) + .setDuration(settings.duration) + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationStart(animator: Animator) {} + + override fun onAnimationCancel(animator: Animator) { + dispatchAnimationFinished(holder) + pendingRemoveAnimations.remove(holder) + view.translationY = 0f + } + + override fun onAnimationEnd(animator: Animator) { + dispatchAnimationFinished(holder) + pendingRemoveAnimations.remove(holder) animation.setListener(null) } }).start() } override fun endAnimation(viewHolder: ViewHolder) { - // Nothing to do + viewHolder.itemView.clearAnimation() + dispatchAnimationFinished(viewHolder) + pendingAddAnimations.remove(viewHolder) + pendingRemoveAnimations.remove(viewHolder) + pendingMoveAnimations.remove(viewHolder) } override fun endAnimations() { + pendingAddAnimations.forEach { + it.itemView.clearAnimation() + dispatchAnimationFinished(it) + } + pendingAddAnimations.clear() + + pendingRemoveAnimations.forEach { + it.itemView.clearAnimation() + dispatchAnimationFinished(it) + } + pendingRemoveAnimations.clear() + + pendingMoveAnimations.forEach { + it.itemView.clearAnimation() + dispatchAnimationFinished(it) + } + pendingMoveAnimations.clear() + expandableAnimator.cancelAnimations() } override fun isRunning(): Boolean { - return isRunning - } - - private fun findParentFor(viewHolder: ViewHolder): Pair? { - val items = adapter.getItems() - val adapterPosition = viewHolder.absoluteAdapterPosition - val groupPosition = items.findIndexByStep(fromPosition = adapterPosition, -1) { it is ExpandableParentItem } ?: return null - - return groupPosition to items[groupPosition] as ExpandableParentItem + return addAnimations.isNotEmpty() || + removeAnimations.isNotEmpty() || + moveAnimations.isNotEmpty() || + pendingAddAnimations.isNotEmpty() || + pendingRemoveAnimations.isNotEmpty() || + pendingMoveAnimations.isNotEmpty() } } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt index 714ed8a6ef..bc3dac2bc8 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt @@ -2,28 +2,19 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable import android.graphics.Canvas import android.graphics.Rect +import android.util.Log import android.view.View import androidx.core.view.children import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.ViewHolder -import io.novafoundation.nova.common.utils.findByStep -import io.novafoundation.nova.common.utils.groupSequentially +import io.novafoundation.nova.common.utils.indexOfFirstOrNull import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimationItemState import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem -private class ItemWithViewHolder(val position: Int, val item: ExpandableBaseItem, val viewHolder: RecyclerView.ViewHolder?) - -interface GroupAnimationDecoration { - fun onDraw( - canvas: Canvas, - expandableItemState: ExpandableAnimationItemState, - parent: RecyclerView, - groupViewHolder: ViewHolder, - items: List - ) -} +private data class ItemWithViewHolder(val position: Int, val item: ExpandableBaseItem, val viewHolder: ViewHolder?) abstract class ExpandableItemDecoration( private val adapter: ExpandableAdapter, @@ -42,38 +33,50 @@ abstract class ExpandableItemDecoration( } - override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) { - val items = try { - getParentAndChildren(parent) - } catch (e: Exception) { - emptyMap() - } + override fun onDraw(canvas: Canvas, recyclerView: RecyclerView, state: RecyclerView.State) { + val items = getParentAndChildren(recyclerView) + + Log.d( + "ExpandableItemDecoration", + items.map { (key, values) -> key.item.getId() + " " + values.map { it.item.getId() }.joinToString { it } }.joinToString { it } + ) for ((parentItem, children) in items) { val animationState = animator.getStateForPosition(parentItem.position) ?: continue val childViewHolders = children.mapNotNull { it.viewHolder } - onDrawGroup(canvas, animationState, parent, parentItem.viewHolder, childViewHolders) + onDrawGroup(canvas, animationState, recyclerView, parentItem.viewHolder, childViewHolders) } } - private fun getParentAndChildren(parent: RecyclerView): Map> { - return parent.children.toList() + private fun getParentAndChildren(recyclerView: RecyclerView): Map> { + val items = recyclerView.children.toList() .mapNotNull { - val position = parent.getChildAdapterPosition(it) - 1 - val viewHolder = parent.getChildViewHolder(it) - val item = adapter.getItemFor(viewHolder) ?: return@mapNotNull null - ItemWithViewHolder(position, item, viewHolder) + val viewHolder = recyclerView.getChildViewHolder(it) + val expandableViewHolder = viewHolder as? ExpandableBaseViewHolder<*> ?: return@mapNotNull null + val item = expandableViewHolder.expandableItem ?: return@mapNotNull null + ItemWithViewHolder(viewHolder.bindingAdapterPosition, item, viewHolder) } - .sortedBy { it.position } - .groupSequentially( - isKey = { it.item is ExpandableParentItem }, - keyForEmptyValue = { getParentForPosition(it.position) } - ) - } - private fun getParentForPosition(position: Int): ItemWithViewHolder { - val item = adapter.getItems().findByStep(fromPosition = position, -1) { it is ExpandableParentItem } + val parents = items.filter { it.item is ExpandableParentItem }.associateBy { it.item.getId() } + val children = items.filter { it.item is ExpandableChildItem } + val parentsWithChildren = mutableMapOf>() + + parents.values.forEach { parentsWithChildren[it] = mutableListOf() } + + children.forEach { child -> + val item = child.item as ExpandableChildItem + val parent = parents[item.groupId] ?: getParentForItem(recyclerView, item) ?: return@forEach + val parentChildren = parentsWithChildren[parent] ?: mutableListOf() + parentChildren.add(child) + parentsWithChildren[parent] = parentChildren + } + + return parentsWithChildren + } - return ItemWithViewHolder(position, item as ExpandableParentItem, null) + private fun getParentForItem(recyclerView: RecyclerView, item: ExpandableChildItem): ItemWithViewHolder? { + val position = adapter.getItems().indexOfFirstOrNull { it.getId() == item.groupId } ?: return null + val parentItem = adapter.getItems()[position] + return ItemWithViewHolder(position, parentItem as ExpandableParentItem, recyclerView.findViewHolderForAdapterPosition(position + 1)) } } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableParentViewHolder.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableParentViewHolder.kt new file mode 100644 index 0000000000..2c22f3a66e --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableParentViewHolder.kt @@ -0,0 +1,22 @@ +package io.novafoundation.nova.common.utils.recyclerView.expandable + +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem + +interface ExpandableBaseViewHolder { + var expandableItem: T? +} + +/** + * The view holder that may show ExpandableChildItem's + * It's used to check the type of viewHolder in [ExpandableItemDecoration] + */ +interface ExpandableParentViewHolder : ExpandableBaseViewHolder + +/** + * The view holder that is shown as an ExpandableChildItem + * It's used to check the type of viewHolder in [ExpandableItemDecoration] + */ +interface ExpandableChildViewHolder : ExpandableBaseViewHolder + diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableViewHolder.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableViewHolder.kt deleted file mode 100644 index 06c6fa6b3c..0000000000 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableViewHolder.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.novafoundation.nova.common.utils.recyclerView.expandable - -/** - * The view holder that may show ExpandingItem's - * It's used to check the type of viewHolder in [ExpandableItemDecoration] - */ -interface ExpandableViewHolder - diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableChildItem.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableChildItem.kt index ac55e73737..902d8a1e72 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableChildItem.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableChildItem.kt @@ -3,4 +3,7 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable.items /** * The item that may be shown or hidden From ExpandableItem */ -interface ExpandableChildItem : ExpandableBaseItem +interface ExpandableChildItem : ExpandableBaseItem { + + val groupId: String +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt index 6b72d2771e..f4d4162a2c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt @@ -9,6 +9,7 @@ import android.graphics.Path import android.graphics.Rect import android.graphics.RectF import android.view.View +import androidx.core.graphics.toRect import androidx.recyclerview.widget.RecyclerView import io.novafoundation.nova.common.utils.dp import io.novafoundation.nova.common.utils.dpF @@ -20,6 +21,7 @@ import io.novafoundation.nova.common.utils.recyclerView.expandable.expandingFrac import io.novafoundation.nova.common.utils.recyclerView.expandable.flippedFraction import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetGroupViewHolder +import kotlin.math.roundToInt class AssetTokensDecoration( private val context: Context, @@ -79,6 +81,25 @@ class AssetTokensDecoration( val childrenBlockBounds = getChildrenBlockBounds(animationState, recyclerView, parent, children) drawChildrenBlock(expandingFraction, childrenBlockBounds, canvas) + clipChildren(children, childrenBlockBounds) + } + + private fun clipChildren(children: List, childrenBlockBounds: RectF) { + val childrenBlock = childrenBlockBounds.toRect() + children.forEach { + val childrenBottomClipInset = it.itemView.bottom - childrenBlock.bottom + val childrenTopClipInset = it.itemView.top - childrenBlock.top + if (childrenBottomClipInset > 0) { + it.itemView.clipBounds = Rect( + 0, + childrenTopClipInset.coerceAtLeast(0), + it.itemView.width, + it.itemView.height - childrenBottomClipInset + ) + } else { + it.itemView.clipBounds = null + } + } } private fun drawChildrenBlock(expandingFraction: Float, childrenBlockBounds: RectF, canvas: Canvas) { @@ -105,19 +126,31 @@ class AssetTokensDecoration( private fun drawParentDivider( expandingFraction: Float, - dividerMargin: Float, + dividerHorizontalMargin: Float, canvas: Canvas, parentBounds: RectF ) { linePaint.color = argbEvaluator.evaluate(expandingFraction, transparentColor, dividerColor) as Int - canvas.drawLine(parentBounds.left + dividerMargin, parentBounds.bottom, parentBounds.right - dividerMargin, parentBounds.bottom, linePaint) + canvas.drawLine( + parentBounds.left + dividerHorizontalMargin, + parentBounds.bottom, + parentBounds.right - dividerHorizontalMargin, + parentBounds.bottom, + linePaint + ) } - private fun parentBounds(parent: RecyclerView.ViewHolder?): RectF? { if (parent == null) return null - return parent.itemView.let { RectF(it.left.toFloat(), it.top.toFloat(), it.right.toFloat(), it.bottom.toFloat()) } + return parent.itemView.let { + RectF( + it.left.toFloat(), + it.top.toFloat() + it.translationY, + it.right.toFloat(), + it.bottom.toFloat() + it.translationY + ) + } } private fun getChildrenBlockBounds( @@ -126,10 +159,12 @@ class AssetTokensDecoration( parent: RecyclerView.ViewHolder?, children: List ): RectF { - val lastChild = children.lastOrNull() + val lastChild = children.maxByOrNull { it.itemView.bottom } + + val translationY = parent?.itemView?.translationY ?: 0f - val top = parent?.itemView?.bottom ?: recyclerView.top - val bottom = lastChild?.itemView?.bottom ?: top // In case if last child is null -> content is empty and we will draw the empty and collapsed block + val top = (parent?.itemView?.bottom ?: recyclerView.top) + translationY + val bottom = (lastChild?.itemView?.bottom?.toFloat() ?: top).coerceAtLeast(top) val left = parent?.itemView?.left ?: lastChild?.itemView?.left ?: recyclerView.left val right = parent?.itemView?.right ?: lastChild?.itemView?.right ?: recyclerView.right @@ -138,7 +173,7 @@ class AssetTokensDecoration( val heightDelta = (bottom - top) return RectF( left + childrenBlockCollapsedHorizontalMargin * flippedExpandingFraction, - top.toFloat(), + top, right - childrenBlockCollapsedHorizontalMargin * flippedExpandingFraction, top + childrenBlockCollapsedHeight + heightDelta * expandingFraction ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt index bb9707cc3a..6ceb773c88 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt @@ -10,7 +10,6 @@ import io.novafoundation.nova.common.list.PayloadGenerator import io.novafoundation.nova.common.list.resolvePayload import io.novafoundation.nova.common.utils.inflateChild import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAdapter -import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableViewHolder import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetGroupViewHolder diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt index 5457ce674f..c166b2b996 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt @@ -2,14 +2,14 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import io.novafoundation.nova.common.list.GroupedListHolder -import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableViewHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableParentViewHolder import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkGroupUi import kotlinx.android.synthetic.main.item_network_asset_group.view.itemAssetGroupBalance import kotlinx.android.synthetic.main.item_network_asset_group.view.itemAssetGroupChain class NetworkAssetGroupViewHolder( containerView: View, -) : GroupedListHolder(containerView), ExpandableViewHolder { +) : GroupedListHolder(containerView) { fun bind(assetGroup: NetworkGroupUi) = with(containerView) { itemAssetGroupChain.setChain(assetGroup.chainUi) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt index 1444928355..44b5fb42c7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt @@ -3,7 +3,8 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder -import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableViewHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableChildViewHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter @@ -19,9 +20,10 @@ import kotlinx.android.synthetic.main.item_network_asset.view.itemAssetToken class NetworkAssetViewHolder( containerView: View, private val imageLoader: ImageLoader, -) : GroupedListHolder(containerView), ExpandableViewHolder { +) : GroupedListHolder(containerView) { fun bind(networkAsset: NetworkAssetUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { + val asset = networkAsset.asset itemAssetImage.loadTokenIcon(asset.token.configuration.iconUrl, imageLoader) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt index b24a66df62..92f03df93e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt @@ -3,7 +3,8 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder -import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableViewHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableParentViewHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter @@ -19,9 +20,13 @@ import kotlinx.android.synthetic.main.item_token_asset_group.view.itemTokenGroup class TokenAssetGroupViewHolder( containerView: View, private val imageLoader: ImageLoader, -) : GroupedListHolder(containerView), ExpandableViewHolder { +) : GroupedListHolder(containerView), ExpandableParentViewHolder { + + override var expandableItem: ExpandableParentItem? = null fun bind(tokenGroup: TokenGroupUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { + expandableItem = tokenGroup + itemTokenGroupAssetImage.loadTokenIcon(tokenGroup.tokenIcon, imageLoader) bindPriceRate(tokenGroup) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt index b6c6c6027f..89cd9792a5 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt @@ -3,7 +3,8 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder -import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableViewHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableChildViewHolder +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi @@ -18,9 +19,13 @@ import kotlinx.android.synthetic.main.item_token_asset.view.itemTokenAssetPriceA class TokenAssetViewHolder( containerView: View, private val imageLoader: ImageLoader, -) : GroupedListHolder(containerView), ExpandableViewHolder { +) : GroupedListHolder(containerView), ExpandableChildViewHolder { + + override var expandableItem: ExpandableChildItem? = null fun bind(tokenAsset: TokenAssetUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { + expandableItem = tokenAsset + val asset = tokenAsset.asset itemTokenAssetImage.loadTokenIcon(asset.token.configuration.iconUrl, imageLoader) itemTokenAssetChainIcon.loadTokenIcon(tokenAsset.chain.icon, imageLoader) @@ -37,4 +42,5 @@ class TokenAssetViewHolder( containerView.itemTokenAssetBalance.text = asset.amount.token containerView.itemTokenAssetPriceAmount.text = asset.amount.fiat } + } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt index c352bb6d15..50a8bd4f2f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt @@ -20,23 +20,24 @@ fun GroupedList.mapGroupedAssetsToU balance: (TotalAndTransferableBalance) -> Amount = TotalAndTransferableBalance::total, ): List { return mapKeys { (assetGroup, _) -> mapAssetGroupToUi(assetGroup, currency, groupBalance) } - .mapValues { (_, assets) -> mapAssetsToAssetModels(assets, balance) } + .mapValues { (group, assets) -> mapAssetsToAssetModels(group, assets, balance) } .toListWithHeaders() .filterIsInstance() } private fun mapAssetsToAssetModels( + group: NetworkGroupUi, assets: List, balance: (TotalAndTransferableBalance) -> Amount ): List { - return assets.map { NetworkAssetUi(mapAssetToAssetModel(it.asset, balance(it.balanceWithOffchain))) } + return assets.map { NetworkAssetUi(group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffchain))) } } private fun mapAssetGroupToUi( assetGroup: NetworkAssetGroup, currency: Currency, groupBalance: (NetworkAssetGroup) -> BigDecimal -): BalanceListRvItem { +): NetworkGroupUi { return NetworkGroupUi( chainUi = mapChainToUi(assetGroup.chain), groupBalanceFiat = groupBalance(assetGroup).formatAsCurrency(currency) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index 54d853825f..f3a86d6779 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -21,22 +21,23 @@ fun GroupedList.mapGroupedAssetsToUi( balance: (TotalAndTransferableBalance) -> Amount = TotalAndTransferableBalance::total, ): List { return mapKeys { (assetGroup, _) -> mapAssetGroupToUi(assetGroup, groupBalance) } - .mapValues { (_, assets) -> mapAssetsToAssetModels(assets, balance) } + .mapValues { (group, assets) -> mapAssetsToAssetModels(group, assets, balance) } .toListWithHeaders() .filterIsInstance() } private fun mapAssetsToAssetModels( + group: TokenGroupUi, assets: List, balance: (TotalAndTransferableBalance) -> Amount ): List { - return assets.map { TokenAssetUi(mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } + return assets.map { TokenAssetUi(group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } } private fun mapAssetGroupToUi( assetGroup: TokenAssetGroup, groupBalance: (TokenAssetGroup) -> Amount -): BalanceListRvItem { +): TokenGroupUi { val balance = groupBalance(assetGroup) return TokenGroupUi( tokenIcon = assetGroup.token.icon, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index 9897a501a9..2e487cb8bb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -78,7 +78,7 @@ class BalanceListFragment : //balanceListAssets.addItemDecoration(decoration) //balanceListAssets.itemAnimator = AssetTokensItemAnimator(assetsAdapter, decoration, balanceListAssets) - val settings = ExpandableAnimationSettings(5000, AccelerateDecelerateInterpolator()) + val settings = ExpandableAnimationSettings(400, AccelerateDecelerateInterpolator()) val animator = ExpandableAnimator(balanceListAssets, settings, assetsAdapter) val decoration = AssetTokensDecoration(requireContext(), assetsAdapter, animator) val itemAnimator = ExpandableItemAnimator(assetsAdapter, settings, animator) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt index 9681dec323..2a17ab3ea6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt @@ -3,6 +3,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list.model.it import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.runtime.ext.fullId -data class NetworkAssetUi(override val asset: AssetModel) : AssetRvItem { +data class NetworkAssetUi(override val groupId: String, override val asset: AssetModel) : AssetRvItem { override val itemId: String = asset.token.configuration.fullId.toString() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt index 9794524a20..2a55d738db 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt @@ -4,7 +4,7 @@ import io.novafoundation.nova.feature_account_api.presenatation.chain.ChainUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.runtime.ext.fullId -data class TokenAssetUi(override val asset: AssetModel, val chain: ChainUi) : AssetRvItem { +data class TokenAssetUi(override val groupId: String, override val asset: AssetModel, val chain: ChainUi) : AssetRvItem { override val itemId: String = asset.token.configuration.fullId.toString() } From 626f29a0306eb4b34407c92fc6fe2fa7616a59a8 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Tue, 22 Oct 2024 02:23:08 +0200 Subject: [PATCH 09/78] Fix bugs and glitching --- .../expandable/ExpandableItemAnimator.kt | 111 ++++++++++++------ .../expandable/ExpandableItemDecoration.kt | 9 +- .../domain/common/TokenAssetSorting.kt | 4 +- .../balance/common/AssetGroupingDecoration.kt | 12 +- .../balance/common/AssetTokensDecoration.kt | 17 ++- .../common/mappers/TokenAssetMappers.kt | 3 +- .../balance/list/BalanceListFragment.kt | 11 +- .../balance/list/model/items/TokenGroupUi.kt | 1 + 8 files changed, 103 insertions(+), 65 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt index 0978e9a0f3..f1d73feccd 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt @@ -2,13 +2,17 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable import android.animation.Animator import android.animation.AnimatorListenerAdapter +import android.util.Log import androidx.recyclerview.widget.RecyclerView.ViewHolder import androidx.recyclerview.widget.SimpleItemAnimator import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimationItemState import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem - +/** + * Potential problems: + * - If in one time point we have add and move animation or remove and move animation and we cancel move animation - the add or remove animation will be also canceled + */ class ExpandableItemAnimator( private val adapter: ExpandableAdapter, private val settings: ExpandableAnimationSettings, @@ -42,8 +46,8 @@ class ExpandableItemAnimator( pendingRemoveAnimations.remove(holder) } else { holder.itemView.alpha = 0f - holder.itemView.scaleX = 0.95f - holder.itemView.scaleY = 0.95f + holder.itemView.scaleX = 0.90f + holder.itemView.scaleY = 0.90f } //val position = viewHolder.absoluteAdapterPosition - parentPosition @@ -51,6 +55,9 @@ class ExpandableItemAnimator( val itemKey = parentItem.toKey() val currentViewHolders = addAnimations[itemKey] ?: emptyList() addAnimations[itemKey] = currentViewHolders + listOf(holder) + + expandableAnimator.animateItemToState(parentItem, ExpandableAnimationItemState.Type.EXPANDING) + return true } @@ -67,26 +74,30 @@ class ExpandableItemAnimator( holder.itemView.alpha = 1f holder.itemView.scaleX = 1f holder.itemView.scaleY = 1f - holder.itemView.translationY = 0f } val itemKey = parentItem.toKey() val currentViewHolders = removeAnimations[itemKey] ?: emptyList() removeAnimations[itemKey] = currentViewHolders + listOf(holder) + + expandableAnimator.animateItemToState(parentItem, ExpandableAnimationItemState.Type.COLLAPSING) + return true } override fun animateMove(holder: ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int): Boolean { + if (holder !is ExpandableBaseViewHolder<*>) return false + if (pendingMoveAnimations.contains(holder)) { - //holder.itemView.animate().cancel() - //pendingMoveAnimations.remove(holder) + holder.itemView.animate().cancel() + pendingMoveAnimations.remove(holder) } else { - val yDelta = toY - fromY - holder.itemView.translationY = -yDelta.toFloat() + //val yDelta = toY - fromY + //holder.itemView.translationY = -yDelta.toFloat() } - val yDelta = toY - fromY - holder.itemView.translationY = -yDelta.toFloat() + val yDelta = toY - fromY - holder.itemView.translationY + holder.itemView.translationY = -yDelta moveAnimations.add(holder) return true } @@ -119,7 +130,7 @@ class ExpandableItemAnimator( val animatingViewHolders = animationGroup.flatMap { (_, viewHolders) -> viewHolders } animationGroup.clear() - parentItems.forEach { expandableAnimator.animateItemToState(it.item, toState) } + //parentItems.forEach { expandableAnimator.animateItemToState(it.item, toState) } for (holder in animatingViewHolders) { runAnimation(holder) } @@ -138,15 +149,11 @@ class ExpandableItemAnimator( override fun onAnimationStart(animator: Animator) {} override fun onAnimationCancel(animator: Animator) { - dispatchAnimationFinished(holder) - pendingAddAnimations.remove(holder) - view.alpha = 1f - view.scaleX = 1f + //addFinished(holder) } override fun onAnimationEnd(animator: Animator) { - dispatchAnimationFinished(holder) - pendingAddAnimations.remove(holder) + addFinished(holder) animation.setListener(null) } }).start() @@ -156,22 +163,18 @@ class ExpandableItemAnimator( val view = holder.itemView val animation = view.animate() animation.alpha(0f) - .scaleX(0.95f) - .scaleY(0.95f) + .scaleX(0.90f) + .scaleY(0.90f) .setDuration(settings.duration) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationStart(animator: Animator) {} override fun onAnimationCancel(animator: Animator) { - dispatchAnimationFinished(holder) - pendingRemoveAnimations.remove(holder) - view.alpha = 0f - view.scaleX = 0.95f + //removeFinished(holder) } override fun onAnimationEnd(animator: Animator) { - dispatchAnimationFinished(holder) - pendingRemoveAnimations.remove(holder) + removeFinished(holder) animation.setListener(null) } }).start() @@ -186,46 +189,59 @@ class ExpandableItemAnimator( override fun onAnimationStart(animator: Animator) {} override fun onAnimationCancel(animator: Animator) { - dispatchAnimationFinished(holder) - pendingRemoveAnimations.remove(holder) - view.translationY = 0f + //moveFinished(holder) } override fun onAnimationEnd(animator: Animator) { - dispatchAnimationFinished(holder) - pendingRemoveAnimations.remove(holder) + moveFinished(holder) animation.setListener(null) } }).start() } override fun endAnimation(viewHolder: ViewHolder) { + Log.d("ExpandableItemAnimator", "add:" + addAnimations.size.toString()) + Log.d("ExpandableItemAnimator", "remove:" + removeAnimations.size.toString()) + Log.d("ExpandableItemAnimator", "move:" + moveAnimations.size.toString()) + viewHolder.itemView.clearAnimation() + + if (pendingAddAnimations.remove(viewHolder)) { + viewHolder.itemView.alpha = 1f + } + if (pendingRemoveAnimations.remove(viewHolder)) { + viewHolder.itemView.alpha = 0f + } + if (pendingMoveAnimations.remove(viewHolder)) { + viewHolder.itemView.translationY = 0f + } + dispatchAnimationFinished(viewHolder) - pendingAddAnimations.remove(viewHolder) - pendingRemoveAnimations.remove(viewHolder) - pendingMoveAnimations.remove(viewHolder) } override fun endAnimations() { pendingAddAnimations.forEach { it.itemView.clearAnimation() - dispatchAnimationFinished(it) + dispatchAddFinished(it) } pendingAddAnimations.clear() pendingRemoveAnimations.forEach { it.itemView.clearAnimation() - dispatchAnimationFinished(it) + dispatchRemoveFinished(it) } pendingRemoveAnimations.clear() pendingMoveAnimations.forEach { it.itemView.clearAnimation() - dispatchAnimationFinished(it) + dispatchMoveFinished(it) } pendingMoveAnimations.clear() + addAnimations.clear() + removeAnimations.clear() + moveAnimations.clear() + expandableAnimator.cancelAnimations() } @@ -237,6 +253,29 @@ class ExpandableItemAnimator( pendingRemoveAnimations.isNotEmpty() || pendingMoveAnimations.isNotEmpty() } + + private fun addFinished(holder: ViewHolder) { + pendingAddAnimations.remove(holder) + internalDispatchAnimationFinished(holder) + } + + private fun removeFinished(holder: ViewHolder) { + pendingRemoveAnimations.remove(holder) + internalDispatchAnimationFinished(holder) + } + + private fun moveFinished(holder: ViewHolder) { + pendingMoveAnimations.remove(holder) + internalDispatchAnimationFinished(holder) + } + + private fun internalDispatchAnimationFinished(holder: ViewHolder) { + if (holder in pendingAddAnimations) return + if (holder in pendingRemoveAnimations) return + if (holder in pendingMoveAnimations) return + + dispatchAnimationFinished(holder) + } } private class ItemKey(val item: ExpandableParentItem) { diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt index bc3dac2bc8..d0359dac72 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt @@ -25,6 +25,7 @@ abstract class ExpandableItemDecoration( canvas: Canvas, animationState: ExpandableAnimationItemState, recyclerView: RecyclerView, + parentItem: ExpandableParentItem, parent: ViewHolder?, children: List ) @@ -35,16 +36,10 @@ abstract class ExpandableItemDecoration( override fun onDraw(canvas: Canvas, recyclerView: RecyclerView, state: RecyclerView.State) { val items = getParentAndChildren(recyclerView) - - Log.d( - "ExpandableItemDecoration", - items.map { (key, values) -> key.item.getId() + " " + values.map { it.item.getId() }.joinToString { it } }.joinToString { it } - ) - for ((parentItem, children) in items) { val animationState = animator.getStateForPosition(parentItem.position) ?: continue val childViewHolders = children.mapNotNull { it.viewHolder } - onDrawGroup(canvas, animationState, recyclerView, parentItem.viewHolder, childViewHolders) + onDrawGroup(canvas, animationState, recyclerView, parentItem.item as ExpandableParentItem, parentItem.viewHolder, childViewHolders) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt index d9457f21de..fbe1f7b756 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt @@ -13,7 +13,8 @@ import java.math.BigDecimal class TokenAssetGroup( val token: Token, - val groupBalance: TotalAndTransferableBalance + val groupBalance: TotalAndTransferableBalance, + val itemsCount: Int ) { data class Token( @@ -46,6 +47,7 @@ fun groupAndSortAssetsByToken( TokenAssetGroup( token = token, groupBalance = assets.fold(TotalAndTransferableBalance.ZERO) { acc, element -> acc + element.balanceWithOffChain }, + itemsCount = assets.size ) }.toSortedMap(assetGroupComparator) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetGroupingDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetGroupingDecoration.kt index 895a34efdb..a7ab192efb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetGroupingDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetGroupingDecoration.kt @@ -14,8 +14,6 @@ import io.novafoundation.nova.common.view.shape.getRoundedCornerDrawable import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetGroupViewHolder import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetViewHolder -import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetGroupViewHolder -import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetViewHolder import kotlin.math.roundToInt /** @@ -113,16 +111,14 @@ class AssetGroupingDecoration( } private fun isFinalItemInGroup(nextType: Int?): Boolean { - return nextType == TYPE_NETWORK_GROUP || nextType == TYPE_TOKEN_GROUP || nextType == null + return nextType == TYPE_NETWORK_GROUP || nextType == null } private fun shouldSkip(viewHolder: RecyclerView.ViewHolder): Boolean { - val isGroupViewHolder = viewHolder is NetworkAssetViewHolder || - viewHolder is NetworkAssetGroupViewHolder || - viewHolder is TokenAssetViewHolder || - viewHolder is TokenAssetGroupViewHolder + val isNetworkViewHolder = viewHolder is NetworkAssetViewHolder || + viewHolder is NetworkAssetGroupViewHolder - return viewHolder.bindingAdapterPosition == RecyclerView.NO_POSITION || !isGroupViewHolder + return viewHolder.bindingAdapterPosition == RecyclerView.NO_POSITION || !isNetworkViewHolder } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt index f4d4162a2c..8ac736d085 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt @@ -19,8 +19,10 @@ import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.Expa import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator import io.novafoundation.nova.common.utils.recyclerView.expandable.expandingFraction import io.novafoundation.nova.common.utils.recyclerView.expandable.flippedFraction +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetGroupViewHolder +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import kotlin.math.roundToInt class AssetTokensDecoration( @@ -68,6 +70,7 @@ class AssetTokensDecoration( canvas: Canvas, animationState: ExpandableAnimationItemState, recyclerView: RecyclerView, + parentItem: ExpandableParentItem, parent: RecyclerView.ViewHolder?, children: List ) { @@ -79,6 +82,9 @@ class AssetTokensDecoration( drawParentBlock(flippedExpandingFraction, parentBounds, canvas, expandingFraction) } + //Don't draw children background if it's a single item + if (parentItem is TokenGroupUi && parentItem.groupWithOneItem) return + val childrenBlockBounds = getChildrenBlockBounds(animationState, recyclerView, parent, children) drawChildrenBlock(expandingFraction, childrenBlockBounds, canvas) clipChildren(children, childrenBlockBounds) @@ -87,8 +93,8 @@ class AssetTokensDecoration( private fun clipChildren(children: List, childrenBlockBounds: RectF) { val childrenBlock = childrenBlockBounds.toRect() children.forEach { - val childrenBottomClipInset = it.itemView.bottom - childrenBlock.bottom - val childrenTopClipInset = it.itemView.top - childrenBlock.top + val childrenBottomClipInset = (it.itemView.bottom - it.itemView.translationY.roundToInt()) - childrenBlock.bottom + val childrenTopClipInset = childrenBlock.top - (it.itemView.top - it.itemView.translationY.roundToInt()) if (childrenBottomClipInset > 0) { it.itemView.clipBounds = Rect( 0, @@ -161,9 +167,10 @@ class AssetTokensDecoration( ): RectF { val lastChild = children.maxByOrNull { it.itemView.bottom } - val translationY = parent?.itemView?.translationY ?: 0f + val parentTranslationY = parent?.itemView?.translationY ?: 0f + val childTranslationY = lastChild?.itemView?.translationY ?: 0f - val top = (parent?.itemView?.bottom ?: recyclerView.top) + translationY + val top = (parent?.itemView?.bottom ?: recyclerView.top) + parentTranslationY val bottom = (lastChild?.itemView?.bottom?.toFloat() ?: top).coerceAtLeast(top) val left = parent?.itemView?.left ?: lastChild?.itemView?.left ?: recyclerView.left val right = parent?.itemView?.right ?: lastChild?.itemView?.right ?: recyclerView.right @@ -175,7 +182,7 @@ class AssetTokensDecoration( left + childrenBlockCollapsedHorizontalMargin * flippedExpandingFraction, top, right - childrenBlockCollapsedHorizontalMargin * flippedExpandingFraction, - top + childrenBlockCollapsedHeight + heightDelta * expandingFraction + top + childrenBlockCollapsedHeight + heightDelta * expandingFraction + childTranslationY ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index f3a86d6779..1e4f58a75b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -20,7 +20,7 @@ fun GroupedList.mapGroupedAssetsToUi( groupBalance: (TokenAssetGroup) -> Amount = { it.groupBalance.total }, balance: (TotalAndTransferableBalance) -> Amount = TotalAndTransferableBalance::total, ): List { - return mapKeys { (assetGroup, _) -> mapAssetGroupToUi(assetGroup, groupBalance) } + return mapKeys { (group, _) -> mapAssetGroupToUi(group, groupBalance) } .mapValues { (group, assets) -> mapAssetsToAssetModels(group, assets, balance) } .toListWithHeaders() .filterIsInstance() @@ -45,6 +45,7 @@ private fun mapAssetGroupToUi( recentRateChange = assetGroup.token.coinRate?.recentRateChange.orZero().formatAsChange(), rateChangeColorRes = mapCoinRateChangeColorRes(assetGroup.token.coinRate), tokenSymbol = assetGroup.token.symbol.value, + groupWithOneItem = assetGroup.itemsCount == 1, balance = AmountModel( token = balance.amount.formatTokenAmount(), fiat = balance.fiat.formatAsCurrency(assetGroup.token.currency) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index 2e487cb8bb..9e1ab274a9 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -19,9 +19,11 @@ import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.BalanceBreakdownBottomSheet +import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetGroupingDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensItemAnimator import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter +import io.novafoundation.nova.feature_assets.presentation.balance.common.applyDefaultTo import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetsHeaderAdapter import io.novafoundation.nova.feature_assets.presentation.model.AssetModel @@ -71,18 +73,13 @@ class BalanceListFragment : balanceListAssets.setHasFixedSize(true) balanceListAssets.adapter = adapter - //AssetGroupingDecoration.applyDefaultTo(balanceListAssets, assetsAdapter) - - // modification animations only harm here - //val decoration = AssetTokensDecoration(requireContext(), assetsAdapter) - //balanceListAssets.addItemDecoration(decoration) - //balanceListAssets.itemAnimator = AssetTokensItemAnimator(assetsAdapter, decoration, balanceListAssets) - val settings = ExpandableAnimationSettings(400, AccelerateDecelerateInterpolator()) val animator = ExpandableAnimator(balanceListAssets, settings, assetsAdapter) val decoration = AssetTokensDecoration(requireContext(), assetsAdapter, animator) val itemAnimator = ExpandableItemAnimator(assetsAdapter, settings, animator) + AssetGroupingDecoration.applyDefaultTo(balanceListAssets, assetsAdapter) + balanceListAssets.addItemDecoration(decoration) balanceListAssets.itemAnimator = itemAnimator diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt index 7ca9bfb5be..f788803d4e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt @@ -9,6 +9,7 @@ data class TokenGroupUi( val recentRateChange: String, @ColorRes val rateChangeColorRes: Int, val tokenSymbol: String, + val groupWithOneItem: Boolean, val balance: AmountModel ) : AssetGroupRvItem { override val itemId: String = tokenSymbol From 9a0e7346b9d154985e1f3ae60b466adb45b146e9 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Tue, 22 Oct 2024 10:57:32 +0200 Subject: [PATCH 10/78] Fixed animation crash --- .../expandable/ExpandableItemAnimator.kt | 77 ++++--------------- .../balance/common/AssetTokensDecoration.kt | 4 +- .../balance/list/BalanceListFragment.kt | 3 + 3 files changed, 21 insertions(+), 63 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt index f1d73feccd..7a6c01fdb3 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt @@ -2,7 +2,6 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable import android.animation.Animator import android.animation.AnimatorListenerAdapter -import android.util.Log import androidx.recyclerview.widget.RecyclerView.ViewHolder import androidx.recyclerview.widget.SimpleItemAnimator import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimationItemState @@ -11,7 +10,7 @@ import io.novafoundation.nova.common.utils.recyclerView.expandable.items.Expanda /** * Potential problems: - * - If in one time point we have add and move animation or remove and move animation and we cancel move animation - the add or remove animation will be also canceled + * - If in one time we will run add and move animation or remove and move animation - one of the animation will be cancelled */ class ExpandableItemAnimator( private val adapter: ExpandableAdapter, @@ -19,13 +18,13 @@ class ExpandableItemAnimator( private val expandableAnimator: ExpandableAnimator ) : SimpleItemAnimator() { - private val addAnimations = mutableMapOf>() // Item id to ViewHolder - private val removeAnimations = mutableMapOf>() // Item id to ViewHolder - private val moveAnimations = mutableListOf() // Item id to ViewHolder + private val addAnimations = mutableMapOf>() + private val removeAnimations = mutableMapOf>() + private val moveAnimations = mutableListOf() - private val pendingAddAnimations = mutableSetOf() // Item id to ViewHolder - private val pendingRemoveAnimations = mutableSetOf() // Item id to ViewHolder - private val pendingMoveAnimations = mutableSetOf() // Item id to ViewHolder + private val pendingAddAnimations = mutableSetOf() + private val pendingRemoveAnimations = mutableSetOf() + private val pendingMoveAnimations = mutableSetOf() init { addDuration = settings.duration @@ -50,8 +49,6 @@ class ExpandableItemAnimator( holder.itemView.scaleY = 0.90f } - //val position = viewHolder.absoluteAdapterPosition - parentPosition - //viewHolder.itemView.translationY = 50f - viewHolder.itemView.height / 2f * 0.7f * position val itemKey = parentItem.toKey() val currentViewHolders = addAnimations[itemKey] ?: emptyList() addAnimations[itemKey] = currentViewHolders + listOf(holder) @@ -91,9 +88,6 @@ class ExpandableItemAnimator( if (pendingMoveAnimations.contains(holder)) { holder.itemView.animate().cancel() pendingMoveAnimations.remove(holder) - } else { - //val yDelta = toY - fromY - //holder.itemView.translationY = -yDelta.toFloat() } val yDelta = toY - fromY - holder.itemView.translationY @@ -146,12 +140,6 @@ class ExpandableItemAnimator( .scaleY(1f) .setDuration(settings.duration) .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationStart(animator: Animator) {} - - override fun onAnimationCancel(animator: Animator) { - //addFinished(holder) - } - override fun onAnimationEnd(animator: Animator) { addFinished(holder) animation.setListener(null) @@ -167,12 +155,6 @@ class ExpandableItemAnimator( .scaleY(0.90f) .setDuration(settings.duration) .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationStart(animator: Animator) {} - - override fun onAnimationCancel(animator: Animator) { - //removeFinished(holder) - } - override fun onAnimationEnd(animator: Animator) { removeFinished(holder) animation.setListener(null) @@ -186,12 +168,6 @@ class ExpandableItemAnimator( animation.translationY(0f) .setDuration(settings.duration) .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationStart(animator: Animator) {} - - override fun onAnimationCancel(animator: Animator) { - //moveFinished(holder) - } - override fun onAnimationEnd(animator: Animator) { moveFinished(holder) animation.setListener(null) @@ -200,49 +176,28 @@ class ExpandableItemAnimator( } override fun endAnimation(viewHolder: ViewHolder) { - Log.d("ExpandableItemAnimator", "add:" + addAnimations.size.toString()) - Log.d("ExpandableItemAnimator", "remove:" + removeAnimations.size.toString()) - Log.d("ExpandableItemAnimator", "move:" + moveAnimations.size.toString()) + viewHolder.itemView.animate().cancel() - viewHolder.itemView.clearAnimation() - - if (pendingAddAnimations.remove(viewHolder)) { - viewHolder.itemView.alpha = 1f - } - if (pendingRemoveAnimations.remove(viewHolder)) { - viewHolder.itemView.alpha = 0f - } - if (pendingMoveAnimations.remove(viewHolder)) { - viewHolder.itemView.translationY = 0f - } - - dispatchAnimationFinished(viewHolder) + viewHolder.itemView.translationY = 0f + viewHolder.itemView.alpha = 0f + viewHolder.itemView.alpha = 1f + viewHolder.itemView.scaleX = 1f + viewHolder.itemView.scaleY = 1f } override fun endAnimations() { - pendingAddAnimations.forEach { - it.itemView.clearAnimation() - dispatchAddFinished(it) - } + pendingAddAnimations.forEach { it.itemView.animate().cancel() } pendingAddAnimations.clear() - pendingRemoveAnimations.forEach { - it.itemView.clearAnimation() - dispatchRemoveFinished(it) - } + pendingRemoveAnimations.forEach { it.itemView.animate().cancel() } pendingRemoveAnimations.clear() - pendingMoveAnimations.forEach { - it.itemView.clearAnimation() - dispatchMoveFinished(it) - } + pendingMoveAnimations.forEach { it.itemView.animate().cancel() } pendingMoveAnimations.clear() addAnimations.clear() removeAnimations.clear() moveAnimations.clear() - - expandableAnimator.cancelAnimations() } override fun isRunning(): Boolean { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt index 8ac736d085..d9d6f7cc39 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt @@ -93,8 +93,8 @@ class AssetTokensDecoration( private fun clipChildren(children: List, childrenBlockBounds: RectF) { val childrenBlock = childrenBlockBounds.toRect() children.forEach { - val childrenBottomClipInset = (it.itemView.bottom - it.itemView.translationY.roundToInt()) - childrenBlock.bottom - val childrenTopClipInset = childrenBlock.top - (it.itemView.top - it.itemView.translationY.roundToInt()) + val childrenBottomClipInset = (it.itemView.bottom + it.itemView.translationY.roundToInt()) - childrenBlock.bottom + val childrenTopClipInset = childrenBlock.top - (it.itemView.top + it.itemView.translationY.roundToInt()) if (childrenBottomClipInset > 0) { it.itemView.clipBounds = Rect( 0, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index 9e1ab274a9..753b39a17f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -1,10 +1,13 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list +import android.animation.ValueAnimator import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.animation.AccelerateDecelerateInterpolator +import androidx.core.animation.addListener import androidx.recyclerview.widget.ConcatAdapter import coil.ImageLoader import dev.chrisbanes.insetter.applyInsetter From b92488be38ae89b2f642cc5e2ba6c14a189bcd0d Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Tue, 22 Oct 2024 11:20:18 +0200 Subject: [PATCH 11/78] Run expanding animation as panding animation --- .../expandable/ExpandableItemAnimator.kt | 14 ++++++++------ .../expandable/animator/ExpandableAnimator.kt | 19 ++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt index 7a6c01fdb3..757278d571 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt @@ -53,7 +53,7 @@ class ExpandableItemAnimator( val currentViewHolders = addAnimations[itemKey] ?: emptyList() addAnimations[itemKey] = currentViewHolders + listOf(holder) - expandableAnimator.animateItemToState(parentItem, ExpandableAnimationItemState.Type.EXPANDING) + expandableAnimator.prepareAnimationToState(parentItem, ExpandableAnimationItemState.Type.EXPANDING) return true } @@ -77,7 +77,7 @@ class ExpandableItemAnimator( val currentViewHolders = removeAnimations[itemKey] ?: emptyList() removeAnimations[itemKey] = currentViewHolders + listOf(holder) - expandableAnimator.animateItemToState(parentItem, ExpandableAnimationItemState.Type.COLLAPSING) + expandableAnimator.prepareAnimationToState(parentItem, ExpandableAnimationItemState.Type.COLLAPSING) return true } @@ -101,8 +101,8 @@ class ExpandableItemAnimator( } override fun runPendingAnimations() { - runAnimationFor(addAnimations, pendingAddAnimations, ExpandableAnimationItemState.Type.EXPANDING) { animateAddImpl(it) } - runAnimationFor(removeAnimations, pendingRemoveAnimations, ExpandableAnimationItemState.Type.COLLAPSING) { animateRemoveImpl(it) } + runAnimationFor(addAnimations, pendingAddAnimations) { animateAddImpl(it) } + runAnimationFor(removeAnimations, pendingRemoveAnimations) { animateRemoveImpl(it) } val animatingViewHolders = moveAnimations.toList() moveAnimations.clear() @@ -117,14 +117,13 @@ class ExpandableItemAnimator( private fun runAnimationFor( animationGroup: MutableMap>, pendingAnimations: MutableSet, - toState: ExpandableAnimationItemState.Type, runAnimation: (ViewHolder) -> Unit ) { val parentItems = animationGroup.keys.toList() val animatingViewHolders = animationGroup.flatMap { (_, viewHolders) -> viewHolders } animationGroup.clear() - //parentItems.forEach { expandableAnimator.animateItemToState(it.item, toState) } + parentItems.forEach { expandableAnimator.runAnimationFor(it.item) } for (holder in animatingViewHolders) { runAnimation(holder) } @@ -138,6 +137,7 @@ class ExpandableItemAnimator( animation.alpha(1f) .scaleX(1f) .scaleY(1f) + .setInterpolator(settings.interpolator) .setDuration(settings.duration) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { @@ -153,6 +153,7 @@ class ExpandableItemAnimator( animation.alpha(0f) .scaleX(0.90f) .scaleY(0.90f) + .setInterpolator(settings.interpolator) .setDuration(settings.duration) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { @@ -167,6 +168,7 @@ class ExpandableItemAnimator( val animation = view.animate() animation.translationY(0f) .setDuration(settings.duration) + .setInterpolator(settings.interpolator) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { moveFinished(holder) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt index 1f2547d7a3..3a326daf87 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt @@ -44,13 +44,13 @@ class ExpandableAnimator( return runningAnimations[item.getId()]?.currentState ?: getExpandableItemState(position, items) } - fun animateItemToState(item: ExpandableParentItem, type: ExpandableAnimationItemState.Type) { + fun prepareAnimationToState(item: ExpandableParentItem, type: ExpandableAnimationItemState.Type) { val existingSettings = runningAnimations[item.getId()] // No need to run animation if animation state is running and current type is the same if (existingSettings == null) { val state = ExpandableAnimationItemState(type, 0f) - runAnimationFor(item, state) + setAnimationFor(item, state) } else { // No need to update animation state if it's the same and already running if (existingSettings.currentState.animationType == type) { @@ -59,11 +59,16 @@ class ExpandableAnimator( // Toggle animation state and flipping fraction to continue the animation but to another side val state = ExpandableAnimationItemState(type, existingSettings.currentState.flippedFraction()) - runAnimationFor(item, state) + setAnimationFor(item, state) } } - private fun runAnimationFor(item: ExpandableParentItem, state: ExpandableAnimationItemState) { + fun runAnimationFor(item: ExpandableParentItem) { + val existingSettings = runningAnimations[item.getId()] + existingSettings?.animator?.start() + } + + private fun setAnimationFor(item: ExpandableParentItem, state: ExpandableAnimationItemState) { runningAnimations[item.getId()]?.animator?.cancel() // Cancel previous animation if it's exist val animator = ValueAnimator.ofFloat(state.animationFraction, 1f) @@ -74,13 +79,9 @@ class ExpandableAnimator( state.animationFraction = it.animatedValue as Float recyclerView.invalidate() } // Invalidate recycler view to trigger onDraw in Item Decoration - animator.addListener( - onEnd = { runningAnimations.remove(item.getId()) }, - onCancel = { runningAnimations.remove(item.getId()) } - ) + animator.addListener(onEnd = { runningAnimations.remove(item.getId()) }) runningAnimations[item.getId()] = RunningAnimation(state, animator) - animator.start() } fun cancelAnimations() { From 75e9494a2a5c146f571efc46902ae408c7c1ea15 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Tue, 22 Oct 2024 12:17:13 +0200 Subject: [PATCH 12/78] Make ExpandableItemAnimator abstract --- .../expandable/ExpandableItemAnimator.kt | 98 ++++++------ ...ecoration.kt => AssetNetworkDecoration.kt} | 6 +- .../balance/common/AssetTokensItemAnimator.kt | 143 ++++++------------ .../balance/list/BalanceListFragment.kt | 11 +- .../balance/search/AssetSearchFragment.kt | 4 +- .../presentation/flow/AssetFlowFragment.kt | 4 +- 6 files changed, 102 insertions(+), 164 deletions(-) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/{AssetGroupingDecoration.kt => AssetNetworkDecoration.kt} (97%) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt index 757278d571..e90228e12a 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt @@ -2,24 +2,26 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable import android.animation.Animator import android.animation.AnimatorListenerAdapter +import android.view.ViewPropertyAnimator import androidx.recyclerview.widget.RecyclerView.ViewHolder import androidx.recyclerview.widget.SimpleItemAnimator import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimationItemState import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem /** * Potential problems: * - If in one time we will run add and move animation or remove and move animation - one of the animation will be cancelled */ -class ExpandableItemAnimator( +abstract class ExpandableItemAnimator( private val adapter: ExpandableAdapter, private val settings: ExpandableAnimationSettings, private val expandableAnimator: ExpandableAnimator ) : SimpleItemAnimator() { - private val addAnimations = mutableMapOf>() - private val removeAnimations = mutableMapOf>() + private val addAnimations = mutableMapOf>() + private val removeAnimations = mutableMapOf>() private val moveAnimations = mutableListOf() private val pendingAddAnimations = mutableSetOf() @@ -38,20 +40,18 @@ class ExpandableItemAnimator( if (holder !is ExpandableChildViewHolder) return false val item = holder.expandableItem ?: return false - val parentItem = adapter.getItems().firstOrNull { it.getId() == item.groupId } as? ExpandableParentItem ?: return false + val parentItem = getParentFor(item) ?: return false if (pendingRemoveAnimations.contains(holder)) { holder.itemView.animate().cancel() - pendingRemoveAnimations.remove(holder) } else { - holder.itemView.alpha = 0f - holder.itemView.scaleX = 0.90f - holder.itemView.scaleY = 0.90f + preAddImpl(holder) } val itemKey = parentItem.toKey() - val currentViewHolders = addAnimations[itemKey] ?: emptyList() - addAnimations[itemKey] = currentViewHolders + listOf(holder) + + if (itemKey !in addAnimations) addAnimations[itemKey] = mutableListOf() + addAnimations[itemKey]?.add(holder) expandableAnimator.prepareAnimationToState(parentItem, ExpandableAnimationItemState.Type.EXPANDING) @@ -62,20 +62,18 @@ class ExpandableItemAnimator( if (holder !is ExpandableChildViewHolder) return false val item = holder.expandableItem ?: return false - val parentItem = adapter.getItems().firstOrNull { it.getId() == item.groupId } as? ExpandableParentItem ?: return false + val parentItem = getParentFor(item) ?: return false if (pendingAddAnimations.contains(holder)) { holder.itemView.animate().cancel() - pendingAddAnimations.remove(holder) } else { - holder.itemView.alpha = 1f - holder.itemView.scaleX = 1f - holder.itemView.scaleY = 1f + preRemoveImpl(holder) } val itemKey = parentItem.toKey() - val currentViewHolders = removeAnimations[itemKey] ?: emptyList() - removeAnimations[itemKey] = currentViewHolders + listOf(holder) + + if (itemKey !in removeAnimations) removeAnimations[itemKey] = mutableListOf() + removeAnimations[itemKey]?.add(holder) expandableAnimator.prepareAnimationToState(parentItem, ExpandableAnimationItemState.Type.COLLAPSING) @@ -87,11 +85,9 @@ class ExpandableItemAnimator( if (pendingMoveAnimations.contains(holder)) { holder.itemView.animate().cancel() - pendingMoveAnimations.remove(holder) } - val yDelta = toY - fromY - holder.itemView.translationY - holder.itemView.translationY = -yDelta + preMoveImpl(holder, fromY, toY) moveAnimations.add(holder) return true } @@ -101,9 +97,13 @@ class ExpandableItemAnimator( } override fun runPendingAnimations() { - runAnimationFor(addAnimations, pendingAddAnimations) { animateAddImpl(it) } - runAnimationFor(removeAnimations, pendingRemoveAnimations) { animateRemoveImpl(it) } + //Add animation + expand items + runExpandableAnimationFor(addAnimations, pendingAddAnimations) { animateAddImpl(it) } + + //Remove animation + collapse items + runExpandableAnimationFor(removeAnimations, pendingRemoveAnimations) { animateRemoveImpl(it) } + //Move animation val animatingViewHolders = moveAnimations.toList() moveAnimations.clear() @@ -114,8 +114,8 @@ class ExpandableItemAnimator( pendingMoveAnimations.addAll(animatingViewHolders) } - private fun runAnimationFor( - animationGroup: MutableMap>, + private fun runExpandableAnimationFor( + animationGroup: MutableMap>, pendingAnimations: MutableSet, runAnimation: (ViewHolder) -> Unit ) { @@ -131,13 +131,21 @@ class ExpandableItemAnimator( pendingAnimations.addAll(animatingViewHolders) } - fun animateAddImpl(holder: ViewHolder) { - val view = holder.itemView - val animation = view.animate() - animation.alpha(1f) - .scaleX(1f) - .scaleY(1f) - .setInterpolator(settings.interpolator) + abstract fun preAddImpl(holder: ViewHolder) + + abstract fun getAddAnimator(holder: ViewHolder): ViewPropertyAnimator + + abstract fun preRemoveImpl(holder: ViewHolder) + + abstract fun getRemoveAnimator(holder: ViewHolder): ViewPropertyAnimator + + abstract fun preMoveImpl(holder: ViewHolder, fromY: Int, toY: Int) + + abstract fun getMoveAnimator(holder: ViewHolder): ViewPropertyAnimator + + private fun animateAddImpl(holder: ViewHolder) { + val animation = getAddAnimator(holder) + animation.setInterpolator(settings.interpolator) .setDuration(settings.duration) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { @@ -147,13 +155,9 @@ class ExpandableItemAnimator( }).start() } - fun animateRemoveImpl(holder: ViewHolder) { - val view = holder.itemView - val animation = view.animate() - animation.alpha(0f) - .scaleX(0.90f) - .scaleY(0.90f) - .setInterpolator(settings.interpolator) + private fun animateRemoveImpl(holder: ViewHolder) { + val animation = getRemoveAnimator(holder) + animation.setInterpolator(settings.interpolator) .setDuration(settings.duration) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { @@ -163,12 +167,10 @@ class ExpandableItemAnimator( }).start() } - fun animateMoveImpl(holder: ViewHolder) { - val view = holder.itemView - val animation = view.animate() - animation.translationY(0f) + private fun animateMoveImpl(holder: ViewHolder) { + val animation = getMoveAnimator(holder) + animation.setInterpolator(settings.interpolator) .setDuration(settings.duration) - .setInterpolator(settings.interpolator) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { moveFinished(holder) @@ -179,12 +181,6 @@ class ExpandableItemAnimator( override fun endAnimation(viewHolder: ViewHolder) { viewHolder.itemView.animate().cancel() - - viewHolder.itemView.translationY = 0f - viewHolder.itemView.alpha = 0f - viewHolder.itemView.alpha = 1f - viewHolder.itemView.scaleX = 1f - viewHolder.itemView.scaleY = 1f } override fun endAnimations() { @@ -233,6 +229,10 @@ class ExpandableItemAnimator( dispatchAnimationFinished(holder) } + + private fun getParentFor(item: ExpandableChildItem): ExpandableParentItem? { + return adapter.getItems().firstOrNull { it.getId() == item.groupId } as? ExpandableParentItem + } } private class ItemKey(val item: ExpandableParentItem) { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetGroupingDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetNetworkDecoration.kt similarity index 97% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetGroupingDecoration.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetNetworkDecoration.kt index a7ab192efb..e70ef66089 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetGroupingDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetNetworkDecoration.kt @@ -21,7 +21,7 @@ import kotlin.math.roundToInt * The issue is that this decoration does not currently support partial list updates and assumes it will be iterated over whole list * TODO update decoration to not require this invalidation */ -class AssetGroupingDecoration( +class AssetNetworkDecoration( private val background: Drawable, private val assetsAdapter: ListAdapter<*, *>, context: Context, @@ -122,14 +122,14 @@ class AssetGroupingDecoration( } } -fun AssetGroupingDecoration.Companion.applyDefaultTo( +fun AssetNetworkDecoration.Companion.applyDefaultTo( recyclerView: RecyclerView, adapter: ListAdapter<*, *> ) { val groupBackground = with(recyclerView.context) { addRipple(getRoundedCornerDrawable(R.color.block_background)) } - val decoration = AssetGroupingDecoration( + val decoration = AssetNetworkDecoration( background = groupBackground, assetsAdapter = adapter, context = recyclerView.context, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt index 0e9a4077aa..77f14aea26 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt @@ -1,122 +1,65 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common -import android.animation.Animator -import android.animation.AnimatorListenerAdapter +import android.view.ViewPropertyAnimator import androidx.recyclerview.widget.RecyclerView -import androidx.recyclerview.widget.RecyclerView.ItemAnimator -import androidx.recyclerview.widget.RecyclerView.ViewHolder -import io.novafoundation.nova.common.utils.findIndexByStep -import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetViewHolder -import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAdapter +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAnimationSettings +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableItemAnimator +import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator class AssetTokensItemAnimator( - private val adapter: BalanceListAdapter, - private val decoration: AssetTokensDecoration, - private val recyclerView: BalanceListRecyclerView -) : ItemAnimator() { - - private var isRunning = false - - private val pendingAnimations = mutableListOf() - - init { - addDuration = 500 - moveDuration = 500 - changeDuration = 500 - } - - override fun onAnimationFinished(viewHolder: ViewHolder) { - recyclerView.invalidate() - } - - - override fun animateDisappearance(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo, postLayoutInfo: ItemHolderInfo?): Boolean { - viewHolder.itemView.alpha = 0f - return true + adapter: ExpandableAdapter, + settings: ExpandableAnimationSettings, + expandableAnimator: ExpandableAnimator +) : ExpandableItemAnimator( + adapter, + settings, + expandableAnimator +) { + override fun preAddImpl(holder: RecyclerView.ViewHolder) { + holder.itemView.alpha = 0f + holder.itemView.scaleX = 0.90f + holder.itemView.scaleY = 0.90f } - override fun animateAppearance(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo?, postLayoutInfo: ItemHolderInfo): Boolean { - if (viewHolder !is TokenAssetViewHolder) return false - viewHolder.itemView.alpha = 0f - viewHolder.itemView.scaleX = 0.7f - viewHolder.itemView.scaleY = 0.7f - - val adapterPosition = viewHolder.absoluteAdapterPosition - val groupPosition = adapter.currentList.findIndexByStep(fromPosition = adapterPosition, -1) { it is TokenGroupUi } ?: return false - val position = viewHolder.absoluteAdapterPosition - groupPosition - viewHolder.itemView.translationY = 50f - viewHolder.itemView.height / 2f * 0.7f * position - pendingAnimations.add(viewHolder) - return true + override fun getAddAnimator(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { + return holder.itemView.animate() + .alpha(1f) + .scaleX(1f) + .scaleY(1f) } - override fun animatePersistence(viewHolder: ViewHolder, preLayoutInfo: ItemHolderInfo, postLayoutInfo: ItemHolderInfo): Boolean { - return false + override fun preRemoveImpl(holder: RecyclerView.ViewHolder) { + holder.itemView.alpha = 1f + holder.itemView.scaleX = 1f + holder.itemView.scaleY = 1f } - override fun animateChange( - oldHolder: ViewHolder, - newHolder: ViewHolder, - preLayoutInfo: ItemHolderInfo, - postLayoutInfo: ItemHolderInfo - ): Boolean { - return true + override fun getRemoveAnimator(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { + return holder.itemView.animate() + .alpha(0f) + .scaleX(0.90f) + .scaleY(0.90f) } - override fun runPendingAnimations() { - val additions = ArrayList() - additions.addAll(pendingAnimations) - pendingAnimations.clear() - val adder = Runnable { - for (holder in additions) { - animateAddImpl(holder) - } - additions.clear() - } - - adder.run() + override fun preMoveImpl(holder: RecyclerView.ViewHolder, fromY: Int, toY: Int) { + val yDelta = toY - fromY + holder.itemView.translationY += -yDelta } - fun animateAddImpl(holder: ViewHolder) { - val view = holder.itemView - val animation = view.animate() - animation.alpha(1f) - .scaleX(1f) - .scaleY(1f) - .setDuration(500) + override fun getMoveAnimator(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { + return holder.itemView.animate() .translationY(0f) - .setUpdateListener { - recyclerView.invalidate() - } - .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationStart(animator: Animator) { - recyclerView.invalidate() - isRunning = true - } - - override fun onAnimationCancel(animator: Animator) { - recyclerView.invalidate() - isRunning = false - view.alpha = 1f - view.scaleX = 1f - } - - override fun onAnimationEnd(animator: Animator) { - recyclerView.invalidate() - isRunning = false - animation.setListener(null) - } - }).start() } - override fun endAnimation(item: ViewHolder) { + override fun endAnimation(viewHolder: RecyclerView.ViewHolder) { + super.endAnimation(viewHolder) - } - - override fun endAnimations() { - } - - override fun isRunning(): Boolean { - return isRunning + viewHolder.itemView.translationY = 0f + viewHolder.itemView.alpha = 0f + viewHolder.itemView.alpha = 1f + viewHolder.itemView.scaleX = 1f + viewHolder.itemView.scaleY = 1f } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index 753b39a17f..2375f1a31f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -1,13 +1,10 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list -import android.animation.ValueAnimator import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.animation.AccelerateDecelerateInterpolator -import androidx.core.animation.addListener import androidx.recyclerview.widget.ConcatAdapter import coil.ImageLoader import dev.chrisbanes.insetter.applyInsetter @@ -15,14 +12,12 @@ import io.novafoundation.nova.common.base.BaseFragment import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.hideKeyboard import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAnimationSettings -import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableItemAnimator -import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableItemDecoration import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.BalanceBreakdownBottomSheet -import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetGroupingDecoration +import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetNetworkDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensItemAnimator import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter @@ -79,9 +74,9 @@ class BalanceListFragment : val settings = ExpandableAnimationSettings(400, AccelerateDecelerateInterpolator()) val animator = ExpandableAnimator(balanceListAssets, settings, assetsAdapter) val decoration = AssetTokensDecoration(requireContext(), assetsAdapter, animator) - val itemAnimator = ExpandableItemAnimator(assetsAdapter, settings, animator) + val itemAnimator = AssetTokensItemAnimator(assetsAdapter, settings, animator) - AssetGroupingDecoration.applyDefaultTo(balanceListAssets, assetsAdapter) + AssetNetworkDecoration.applyDefaultTo(balanceListAssets, assetsAdapter) balanceListAssets.addItemDecoration(decoration) balanceListAssets.itemAnimator = itemAnimator diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt index c2060f979d..cf0f7015d9 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt @@ -18,7 +18,7 @@ import io.novafoundation.nova.common.utils.submitListPreservingViewPoint import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent -import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetGroupingDecoration +import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetNetworkDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.common.applyDefaultTo import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi @@ -59,7 +59,7 @@ class AssetSearchFragment : searchAssetList.setHasFixedSize(true) searchAssetList.adapter = assetsAdapter - AssetGroupingDecoration.applyDefaultTo(searchAssetList, assetsAdapter) + AssetNetworkDecoration.applyDefaultTo(searchAssetList, assetsAdapter) searchAssetList.itemAnimator = null searchAssetSearch.cancel.setOnClickListener { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowFragment.kt index 51024d77d0..b9e6d4a0ae 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowFragment.kt @@ -17,7 +17,7 @@ import io.novafoundation.nova.common.utils.keyboard.showSoftKeyboard import io.novafoundation.nova.common.utils.submitListPreservingViewPoint import io.novafoundation.nova.common.view.setModelOrHide import io.novafoundation.nova.feature_assets.R -import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetGroupingDecoration +import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetNetworkDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.common.applyDefaultTo import io.novafoundation.nova.feature_assets.presentation.model.AssetModel @@ -64,7 +64,7 @@ abstract class AssetFlowFragment : setHasFixedSize(true) adapter = assetsAdapter - AssetGroupingDecoration.applyDefaultTo(this, assetsAdapter) + AssetNetworkDecoration.applyDefaultTo(this, assetsAdapter) itemAnimator = null } From edd292c04eb418f5d45014ea4e638f65dadf602c Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Tue, 22 Oct 2024 13:16:17 +0200 Subject: [PATCH 13/78] Clean code and run ktlint --- common/build.gradle | 1 - .../nova/common/utils/ListExt.kt | 26 ------------ .../nova/common/utils/MapExt.kt | 28 ------------- .../expandable/ExpandableAdapter.kt | 1 - .../expandable/ExpandableAnimationExt.kt | 8 ---- .../expandable/ExpandableItemAnimator.kt | 42 +++++++++++++++++-- .../expandable/ExpandableItemDecoration.kt | 35 ++++++++++++---- .../expandable/ExpandableParentViewHolder.kt | 1 - .../expandable/animator/ExpandableAnimator.kt | 6 ++- .../expandable/items/ExpandableBaseItem.kt | 1 - .../expandable/items/ExpandableParentItem.kt | 1 - .../balance/common/AssetTokensDecoration.kt | 2 +- .../balance/common/AssetTokensItemAnimator.kt | 26 ++++++++---- .../balance/common/BalanceListRecyclerView.kt | 28 ------------- .../holders/NetworkAssetGroupViewHolder.kt | 1 - .../common/holders/NetworkAssetViewHolder.kt | 3 -- .../holders/TokenAssetGroupViewHolder.kt | 1 - .../common/holders/TokenAssetViewHolder.kt | 1 - .../balance/list/BalanceListFragment.kt | 12 +++--- .../balance/list/view/AssetViewModeView.kt | 1 - .../main/res/layout/fragment_balance_list.xml | 2 +- 21 files changed, 97 insertions(+), 130 deletions(-) delete mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListRecyclerView.kt diff --git a/common/build.gradle b/common/build.gradle index a9bff9c7d2..0a119a8950 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -93,7 +93,6 @@ dependencies { implementation viewModelKtxDep implementation daggerDep - implementation 'androidx.asynclayoutinflater:asynclayoutinflater:1.0.0' kapt daggerKapt implementation lifecycleDep diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/ListExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/ListExt.kt index 44a4a6f11f..370ceba817 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/ListExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/ListExt.kt @@ -50,29 +50,3 @@ fun List.rangeCheck(fromIndex: Int, toIndex: Int) { toIndex > size -> throw IndexOutOfBoundsException("toIndex ($toIndex) is greater than size ($size).") } } - -fun List.findByStep(fromPosition: Int, step: Int, predicate: (T) -> Boolean): T? { - return findIndexByStep(fromPosition, step, predicate)?.let { get(it) } -} - -fun List.findIndexByStep(fromPosition: Int, step: Int, predicate: (T) -> Boolean): Int? { - if (fromPosition < 0) return null - if (fromPosition >= size) return null - if (step == 0) return null - - var currentPosition = fromPosition - while (currentPosition in 0 until size) { - if (predicate(get(currentPosition))) { - return currentPosition - } - - currentPosition += step - } - - return null -} - -fun Sequence.subList(fromIndex: Int, toIndex: Int): List { - return toList().subList(fromIndex, toIndex) -} - diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/MapExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/MapExt.kt index 72b681b920..9e44175427 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/MapExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/MapExt.kt @@ -8,31 +8,3 @@ inline fun Map.filterValuesIsInstance(): Map { fun mapOfNotNullValues(vararg pairs: Pair): Map { return mapOf(*pairs).filterNotNull() } - -/** - * Groups items Sequentially step by step. Awaits that items is sorted - * Defines a group of elements and puts all subsequent elements in that group until the next group found - * @param keyForEmptyValue - is called when there is no group for item: [Item, Item, Group, Item Item] - for this case will create Group for first two items - */ -fun List.groupSequentially( - isKey: (T) -> Boolean, - keyForEmptyValue: (T) -> T // Generates key if there is no key for value in list -): Map> { - val resultMap = mutableMapOf>() - - var currentValues: MutableList? = null - forEach { - if (isKey(it)) { - currentValues = mutableListOf() - resultMap[it] = currentValues!! - } else { - if (currentValues == null) { - currentValues = mutableListOf() - resultMap[keyForEmptyValue(it)] = currentValues!! - } - currentValues!! += it - } - } - - return resultMap -} diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAdapter.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAdapter.kt index e45135f9c4..2ea0f99561 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAdapter.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAdapter.kt @@ -6,4 +6,3 @@ interface ExpandableAdapter { fun getItems(): List } - diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt index f30c6fd499..a54d6a34cc 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationExt.kt @@ -1,8 +1,6 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable -import androidx.recyclerview.widget.RecyclerView.ViewHolder import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimationItemState -import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem fun ExpandableAnimationItemState.flippedFraction(): Float { return 1f - animationFraction @@ -18,9 +16,3 @@ fun ExpandableAnimationItemState.expandingFraction(): Float { ExpandableAnimationItemState.Type.COLLAPSING -> flippedFraction() } } - -fun ExpandableAdapter.getItemFor(viewHolder: ViewHolder): ExpandableBaseItem? { - if (viewHolder !is ExpandableBaseViewHolder<*>) return null - - return getItems().getOrNull(viewHolder.absoluteAdapterPosition - 1) -} diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt index e90228e12a..5aec22d9a4 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt @@ -12,7 +12,7 @@ import io.novafoundation.nova.common.utils.recyclerView.expandable.items.Expanda /** * Potential problems: - * - If in one time we will run add and move animation or remove and move animation - one of the animation will be cancelled + * - If in one time we will run add and move animation or remove and move animation - one of an animation will be cancelled */ abstract class ExpandableItemAnimator( private val adapter: ExpandableAdapter, @@ -42,6 +42,13 @@ abstract class ExpandableItemAnimator( val parentItem = getParentFor(item) ?: return false + // Reset move state helps clear translationY when animation is being to be canceled + if (pendingMoveAnimations.contains(holder)) { + holder.itemView.animate().cancel() + + resetMoveState(holder) + } + if (pendingRemoveAnimations.contains(holder)) { holder.itemView.animate().cancel() } else { @@ -64,6 +71,13 @@ abstract class ExpandableItemAnimator( val parentItem = getParentFor(item) ?: return false + // Reset move state helps clear translationY when animation is being to be canceled + if (pendingMoveAnimations.contains(holder)) { + holder.itemView.animate().cancel() + + resetMoveState(holder) + } + if (pendingAddAnimations.contains(holder)) { holder.itemView.animate().cancel() } else { @@ -83,6 +97,18 @@ abstract class ExpandableItemAnimator( override fun animateMove(holder: ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int): Boolean { if (holder !is ExpandableBaseViewHolder<*>) return false + // Reset add state helps clear alpha and scale when animation is being to be canceled + if (pendingAddAnimations.contains(holder)) { + holder.itemView.animate().cancel() + resetAddState(holder) + } + + // Reset remove state helps clear alpha and scale when animation is being to be canceled + if (pendingRemoveAnimations.contains(holder)) { + holder.itemView.animate().cancel() + resetRemoveState(holder) + } + if (pendingMoveAnimations.contains(holder)) { holder.itemView.animate().cancel() } @@ -97,13 +123,13 @@ abstract class ExpandableItemAnimator( } override fun runPendingAnimations() { - //Add animation + expand items + // Add animation + expand items runExpandableAnimationFor(addAnimations, pendingAddAnimations) { animateAddImpl(it) } - //Remove animation + collapse items + // Remove animation + collapse items runExpandableAnimationFor(removeAnimations, pendingRemoveAnimations) { animateRemoveImpl(it) } - //Move animation + // Move animation val animatingViewHolders = moveAnimations.toList() moveAnimations.clear() @@ -143,6 +169,12 @@ abstract class ExpandableItemAnimator( abstract fun getMoveAnimator(holder: ViewHolder): ViewPropertyAnimator + abstract fun resetAddState(holder: ViewHolder) + + abstract fun resetRemoveState(holder: ViewHolder) + + abstract fun resetMoveState(holder: ViewHolder) + private fun animateAddImpl(holder: ViewHolder) { val animation = getAddAnimator(holder) animation.setInterpolator(settings.interpolator) @@ -196,6 +228,8 @@ abstract class ExpandableItemAnimator( addAnimations.clear() removeAnimations.clear() moveAnimations.clear() + + expandableAnimator.cancelAnimations() } override fun isRunning(): Boolean { diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt index d0359dac72..ec30ca0b92 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt @@ -2,10 +2,11 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable import android.graphics.Canvas import android.graphics.Rect -import android.util.Log import android.view.View import androidx.core.view.children +import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.Adapter import androidx.recyclerview.widget.RecyclerView.ViewHolder import io.novafoundation.nova.common.utils.indexOfFirstOrNull import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator @@ -31,7 +32,6 @@ abstract class ExpandableItemDecoration( ) override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { - } override fun onDraw(canvas: Canvas, recyclerView: RecyclerView, state: RecyclerView.State) { @@ -44,6 +44,7 @@ abstract class ExpandableItemDecoration( } private fun getParentAndChildren(recyclerView: RecyclerView): Map> { + // Searching all view holders in recycler view and match them with adapter items val items = recyclerView.children.toList() .mapNotNull { val viewHolder = recyclerView.getChildViewHolder(it) @@ -52,10 +53,11 @@ abstract class ExpandableItemDecoration( ItemWithViewHolder(viewHolder.bindingAdapterPosition, item, viewHolder) } - val parents = items.filter { it.item is ExpandableParentItem }.associateBy { it.item.getId() } - val children = items.filter { it.item is ExpandableChildItem } + // Grouping view holders by parents val parentsWithChildren = mutableMapOf>() + val parents = items.filter { it.item is ExpandableParentItem }.associateBy { it.item.getId() } + val children = items.filter { it.item is ExpandableChildItem } parents.values.forEach { parentsWithChildren[it] = mutableListOf() } children.forEach { child -> @@ -70,8 +72,27 @@ abstract class ExpandableItemDecoration( } private fun getParentForItem(recyclerView: RecyclerView, item: ExpandableChildItem): ItemWithViewHolder? { - val position = adapter.getItems().indexOfFirstOrNull { it.getId() == item.groupId } ?: return null - val parentItem = adapter.getItems()[position] - return ItemWithViewHolder(position, parentItem as ExpandableParentItem, recyclerView.findViewHolderForAdapterPosition(position + 1)) + val positionInAdapter = adapter.getItems().indexOfFirstOrNull { it.getId() == item.groupId } ?: return null + val parentItem = adapter.getItems()[positionInAdapter] + val globalAdapterPosition = positionInAdapter.convertToGlobalAdapterPosition(recyclerView, adapter as Adapter<*>) + val viewHolder = recyclerView.findViewHolderForAdapterPosition(globalAdapterPosition) + return ItemWithViewHolder(positionInAdapter, parentItem as ExpandableParentItem, viewHolder) + } + + // Useful to find global position if ConcatAdapter is used + private fun Int.convertToGlobalAdapterPosition(recyclerView: RecyclerView, localAdapter: Adapter<*>): Int { + val globalAdapter = recyclerView.adapter + return if (globalAdapter is ConcatAdapter) { + val localAdapterIndex = globalAdapter.adapters.indexOf(localAdapter) + if (localAdapterIndex > 0) { + val adaptersBeforeTarget = globalAdapter.adapters.subList(0, localAdapterIndex - 1) + val offset = adaptersBeforeTarget.sumOf { it.itemCount } + this + offset + } else { + this + } + } else { + this + } } } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableParentViewHolder.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableParentViewHolder.kt index 2c22f3a66e..503bbcb7b9 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableParentViewHolder.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableParentViewHolder.kt @@ -19,4 +19,3 @@ interface ExpandableParentViewHolder : ExpandableBaseViewHolder - diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt index 3a326daf87..8ee2ca0094 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt @@ -11,7 +11,9 @@ import io.novafoundation.nova.common.utils.recyclerView.expandable.items.Expanda import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem /** - * Where animationFraction = 0f - fully collapsed and animationFraction = 1f - fully expanded + * EXPANDING: animationFraction = 0f - fully collapsed and animationFraction = 1f - fully expanded + * COLLAPSING: animationFraction = 0f - fully expanded and animationFraction = 1f - fully collapsed + * So animationFraction is always move from 0f to 1f */ class ExpandableAnimationItemState(val animationType: Type, animationFraction: Float) { @@ -36,6 +38,7 @@ class ExpandableAnimator( // It contains only items that is animating right now private val runningAnimations = mutableMapOf() + // Return current animation state for parent position or calculate state in [getExpandableItemState] if it isn't animating now fun getStateForPosition(position: Int): ExpandableAnimationItemState? { val items = expandableAdapter.getItems() val item = items[position] @@ -44,6 +47,7 @@ class ExpandableAnimator( return runningAnimations[item.getId()]?.currentState ?: getExpandableItemState(position, items) } + // Just prepare an animation without running fun prepareAnimationToState(item: ExpandableParentItem, type: ExpandableAnimationItemState.Type) { val existingSettings = runningAnimations[item.getId()] diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableBaseItem.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableBaseItem.kt index b49cdd6578..2bcd71970e 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableBaseItem.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableBaseItem.kt @@ -6,4 +6,3 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable.items interface ExpandableBaseItem { fun getId(): String } - diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableParentItem.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableParentItem.kt index e0b38ff0e8..dee85b835e 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableParentItem.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/items/ExpandableParentItem.kt @@ -4,4 +4,3 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable.items * The item that may show ExpandingItem's */ interface ExpandableParentItem : ExpandableBaseItem - diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt index d9d6f7cc39..7303728d4f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt @@ -82,7 +82,7 @@ class AssetTokensDecoration( drawParentBlock(flippedExpandingFraction, parentBounds, canvas, expandingFraction) } - //Don't draw children background if it's a single item + // Don't draw children background if it's a single item if (parentItem is TokenGroupUi && parentItem.groupWithOneItem) return val childrenBlockBounds = getChildrenBlockBounds(animationState, recyclerView, parent, children) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt index 77f14aea26..6bf7e18770 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt @@ -16,10 +16,9 @@ class AssetTokensItemAnimator( settings, expandableAnimator ) { + override fun preAddImpl(holder: RecyclerView.ViewHolder) { - holder.itemView.alpha = 0f - holder.itemView.scaleX = 0.90f - holder.itemView.scaleY = 0.90f + resetRemoveState(holder) } override fun getAddAnimator(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { @@ -30,9 +29,7 @@ class AssetTokensItemAnimator( } override fun preRemoveImpl(holder: RecyclerView.ViewHolder) { - holder.itemView.alpha = 1f - holder.itemView.scaleX = 1f - holder.itemView.scaleY = 1f + resetAddState(holder) } override fun getRemoveAnimator(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { @@ -61,5 +58,20 @@ class AssetTokensItemAnimator( viewHolder.itemView.scaleX = 1f viewHolder.itemView.scaleY = 1f } -} + override fun resetAddState(holder: RecyclerView.ViewHolder) { + holder.itemView.alpha = 1f + holder.itemView.scaleX = 1f + holder.itemView.scaleY = 1f + } + + override fun resetRemoveState(holder: RecyclerView.ViewHolder) { + holder.itemView.alpha = 0f + holder.itemView.scaleX = 0.90f + holder.itemView.scaleY = 0.90f + } + + override fun resetMoveState(holder: RecyclerView.ViewHolder) { + holder.itemView.translationY = 0f + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListRecyclerView.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListRecyclerView.kt deleted file mode 100644 index 979dc24215..0000000000 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListRecyclerView.kt +++ /dev/null @@ -1,28 +0,0 @@ -package io.novafoundation.nova.feature_assets.presentation.balance.common - -import android.content.Context -import android.graphics.Canvas -import android.util.AttributeSet -import androidx.recyclerview.widget.RecyclerView - -class BalanceListRecyclerView @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyle: Int = 0, -) : RecyclerView(context, attrs, defStyle) { - - private var drawingAvailable = true - - init { - setWillNotDraw(false) - } - - override fun onDraw(canvas: Canvas) { - super.onDraw(canvas) - - if (drawingAvailable) { - //drawing.draw(canvas, 0f, 0f) - } - } - -} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt index c166b2b996..352490f828 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetGroupViewHolder.kt @@ -2,7 +2,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import io.novafoundation.nova.common.list.GroupedListHolder -import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableParentViewHolder import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkGroupUi import kotlinx.android.synthetic.main.item_network_asset_group.view.itemAssetGroupBalance import kotlinx.android.synthetic.main.item_network_asset_group.view.itemAssetGroupChain diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt index 44b5fb42c7..36e8d75d6d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt @@ -3,8 +3,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder -import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableChildViewHolder -import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter @@ -23,7 +21,6 @@ class NetworkAssetViewHolder( ) : GroupedListHolder(containerView) { fun bind(networkAsset: NetworkAssetUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { - val asset = networkAsset.asset itemAssetImage.loadTokenIcon(asset.token.configuration.iconUrl, imageLoader) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt index 92f03df93e..6127ea1e1d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt @@ -16,7 +16,6 @@ import kotlinx.android.synthetic.main.item_token_asset_group.view.itemAssetToken import kotlinx.android.synthetic.main.item_token_asset_group.view.itemAssetTokenGroupToken import kotlinx.android.synthetic.main.item_token_asset_group.view.itemTokenGroupAssetImage - class TokenAssetGroupViewHolder( containerView: View, private val imageLoader: ImageLoader, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt index 89cd9792a5..1b298b9bfa 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt @@ -42,5 +42,4 @@ class TokenAssetViewHolder( containerView.itemTokenAssetBalance.text = asset.amount.token containerView.itemTokenAssetPriceAmount.text = asset.amount.fiat } - } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index 2375f1a31f..baa265a6d9 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -71,15 +71,13 @@ class BalanceListFragment : balanceListAssets.setHasFixedSize(true) balanceListAssets.adapter = adapter - val settings = ExpandableAnimationSettings(400, AccelerateDecelerateInterpolator()) - val animator = ExpandableAnimator(balanceListAssets, settings, assetsAdapter) - val decoration = AssetTokensDecoration(requireContext(), assetsAdapter, animator) - val itemAnimator = AssetTokensItemAnimator(assetsAdapter, settings, animator) + val animationSettings = ExpandableAnimationSettings(400, AccelerateDecelerateInterpolator()) + val animator = ExpandableAnimator(balanceListAssets, animationSettings, assetsAdapter) - AssetNetworkDecoration.applyDefaultTo(balanceListAssets, assetsAdapter) + balanceListAssets.addItemDecoration(AssetTokensDecoration(requireContext(), assetsAdapter, animator)) + balanceListAssets.itemAnimator = AssetTokensItemAnimator(assetsAdapter, animationSettings, animator) - balanceListAssets.addItemDecoration(decoration) - balanceListAssets.itemAnimator = itemAnimator + AssetNetworkDecoration.applyDefaultTo(balanceListAssets, assetsAdapter) walletContainer.setOnRefreshListener { viewModel.fullSync() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt index a41082d482..06f4a61693 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/AssetViewModeView.kt @@ -38,7 +38,6 @@ class AssetViewModeView @JvmOverloads constructor( } override fun onAnimationRepeat(animation: Animation?) { - } } diff --git a/feature-assets/src/main/res/layout/fragment_balance_list.xml b/feature-assets/src/main/res/layout/fragment_balance_list.xml index 9440c7c74f..ef69f89765 100644 --- a/feature-assets/src/main/res/layout/fragment_balance_list.xml +++ b/feature-assets/src/main/res/layout/fragment_balance_list.xml @@ -7,7 +7,7 @@ android:layout_height="match_parent" android:background="@drawable/drawable_background_image"> - Date: Wed, 23 Oct 2024 04:15:16 +0200 Subject: [PATCH 14/78] Fixed token->networks bugs + other issues - fixed last item decoration - support single item click - back to collapsable state when change asset view type --- .../expandable/ExpandableItemAnimator.kt | 78 ++++++++----------- .../expandable/animator/ExpandableAnimator.kt | 28 +++---- .../bg_primary_list_item_corner_12.xml | 12 +++ .../domain/common/TokenAssetSorting.kt | 2 + .../balance/common/AssetListMixin.kt | 27 ++++--- .../balance/common/AssetTokensDecoration.kt | 6 +- .../balance/common/AssetTokensItemAnimator.kt | 2 - .../common/mappers/NetworkAssetMappers.kt | 5 +- .../common/mappers/TokenAssetMappers.kt | 29 ++++++- .../balance/list/BalanceListFragment.kt | 8 +- .../balance/list/model/items/AssetRvItem.kt | 4 +- .../list/model/items/NetworkAssetUi.kt | 4 +- .../balance/list/model/items/TokenAssetUi.kt | 5 +- .../balance/list/model/items/TokenGroupUi.kt | 16 +++- .../res/layout/item_token_asset_group.xml | 4 +- 15 files changed, 133 insertions(+), 97 deletions(-) create mode 100644 common/src/main/res/drawable/bg_primary_list_item_corner_12.xml diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt index 5aec22d9a4..b3d440f4c1 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt @@ -7,21 +7,18 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder import androidx.recyclerview.widget.SimpleItemAnimator import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimationItemState import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator -import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem -import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem /** * Potential problems: * - If in one time we will run add and move animation or remove and move animation - one of an animation will be cancelled */ abstract class ExpandableItemAnimator( - private val adapter: ExpandableAdapter, private val settings: ExpandableAnimationSettings, private val expandableAnimator: ExpandableAnimator ) : SimpleItemAnimator() { - private val addAnimations = mutableMapOf>() - private val removeAnimations = mutableMapOf>() + private val addAnimations = mutableMapOf>() // Parent item to children + private val removeAnimations = mutableMapOf>() // Parent item to children private val moveAnimations = mutableListOf() private val pendingAddAnimations = mutableSetOf() @@ -37,10 +34,11 @@ abstract class ExpandableItemAnimator( } override fun animateAdd(holder: ViewHolder): Boolean { - if (holder !is ExpandableChildViewHolder) return false - val item = holder.expandableItem ?: return false - - val parentItem = getParentFor(item) ?: return false + if (holder !is ExpandableChildViewHolder || holder.expandableItem == null) { + dispatchAddFinished(holder) + return true + } + val item = holder.expandableItem!! // Reset move state helps clear translationY when animation is being to be canceled if (pendingMoveAnimations.contains(holder)) { @@ -55,21 +53,20 @@ abstract class ExpandableItemAnimator( preAddImpl(holder) } - val itemKey = parentItem.toKey() - - if (itemKey !in addAnimations) addAnimations[itemKey] = mutableListOf() - addAnimations[itemKey]?.add(holder) + if (item.groupId !in addAnimations) addAnimations[item.groupId] = mutableListOf() + addAnimations[item.groupId]?.add(holder) - expandableAnimator.prepareAnimationToState(parentItem, ExpandableAnimationItemState.Type.EXPANDING) + expandableAnimator.prepareAnimationToState(item.groupId, ExpandableAnimationItemState.Type.EXPANDING) return true } override fun animateRemove(holder: ViewHolder): Boolean { - if (holder !is ExpandableChildViewHolder) return false - val item = holder.expandableItem ?: return false - - val parentItem = getParentFor(item) ?: return false + if (holder !is ExpandableChildViewHolder || holder.expandableItem == null) { + dispatchRemoveFinished(holder) + return false + } + val item = holder.expandableItem!! // Reset move state helps clear translationY when animation is being to be canceled if (pendingMoveAnimations.contains(holder)) { @@ -84,18 +81,19 @@ abstract class ExpandableItemAnimator( preRemoveImpl(holder) } - val itemKey = parentItem.toKey() + if (item.groupId !in removeAnimations) removeAnimations[item.groupId] = mutableListOf() + removeAnimations[item.groupId]?.add(holder) - if (itemKey !in removeAnimations) removeAnimations[itemKey] = mutableListOf() - removeAnimations[itemKey]?.add(holder) - - expandableAnimator.prepareAnimationToState(parentItem, ExpandableAnimationItemState.Type.COLLAPSING) + expandableAnimator.prepareAnimationToState(item.groupId, ExpandableAnimationItemState.Type.COLLAPSING) return true } override fun animateMove(holder: ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int): Boolean { - if (holder !is ExpandableBaseViewHolder<*>) return false + if (holder !is ExpandableBaseViewHolder<*>) { + dispatchMoveFinished(holder) + return false + } // Reset add state helps clear alpha and scale when animation is being to be canceled if (pendingAddAnimations.contains(holder)) { @@ -119,6 +117,12 @@ abstract class ExpandableItemAnimator( } override fun animateChange(oldHolder: ViewHolder?, newHolder: ViewHolder?, fromLeft: Int, fromTop: Int, toLeft: Int, toTop: Int): Boolean { + if (oldHolder == newHolder) { + dispatchChangeFinished(newHolder, false) + } else { + dispatchChangeFinished(oldHolder, true) + dispatchChangeFinished(newHolder, false) + } return false } @@ -141,15 +145,15 @@ abstract class ExpandableItemAnimator( } private fun runExpandableAnimationFor( - animationGroup: MutableMap>, + animationGroup: MutableMap>, pendingAnimations: MutableSet, runAnimation: (ViewHolder) -> Unit ) { - val parentItems = animationGroup.keys.toList() + val parentItemIds = animationGroup.keys.toList() val animatingViewHolders = animationGroup.flatMap { (_, viewHolders) -> viewHolders } animationGroup.clear() - parentItems.forEach { expandableAnimator.runAnimationFor(it.item) } + parentItemIds.forEach { expandableAnimator.runAnimationFor(it) } for (holder in animatingViewHolders) { runAnimation(holder) } @@ -263,24 +267,4 @@ abstract class ExpandableItemAnimator( dispatchAnimationFinished(holder) } - - private fun getParentFor(item: ExpandableChildItem): ExpandableParentItem? { - return adapter.getItems().firstOrNull { it.getId() == item.groupId } as? ExpandableParentItem - } -} - -private class ItemKey(val item: ExpandableParentItem) { - - override fun equals(other: Any?): Boolean { - if (other !is ItemKey) return false - return item.getId() == other.item.getId() - } - - override fun hashCode(): Int { - return item.hashCode() - } -} - -private fun ExpandableParentItem.toKey(): ItemKey { - return ItemKey(this) } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt index 8ee2ca0094..eb54259080 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/animator/ExpandableAnimator.kt @@ -41,20 +41,20 @@ class ExpandableAnimator( // Return current animation state for parent position or calculate state in [getExpandableItemState] if it isn't animating now fun getStateForPosition(position: Int): ExpandableAnimationItemState? { val items = expandableAdapter.getItems() - val item = items[position] + val item = items.getOrNull(position) ?: return null if (item !is ExpandableParentItem) return null return runningAnimations[item.getId()]?.currentState ?: getExpandableItemState(position, items) } // Just prepare an animation without running - fun prepareAnimationToState(item: ExpandableParentItem, type: ExpandableAnimationItemState.Type) { - val existingSettings = runningAnimations[item.getId()] + fun prepareAnimationToState(parentId: String, type: ExpandableAnimationItemState.Type) { + val existingSettings = runningAnimations[parentId] // No need to run animation if animation state is running and current type is the same if (existingSettings == null) { val state = ExpandableAnimationItemState(type, 0f) - setAnimationFor(item, state) + setAnimationFor(parentId, state) } else { // No need to update animation state if it's the same and already running if (existingSettings.currentState.animationType == type) { @@ -63,17 +63,17 @@ class ExpandableAnimator( // Toggle animation state and flipping fraction to continue the animation but to another side val state = ExpandableAnimationItemState(type, existingSettings.currentState.flippedFraction()) - setAnimationFor(item, state) + setAnimationFor(parentId, state) } } - fun runAnimationFor(item: ExpandableParentItem) { - val existingSettings = runningAnimations[item.getId()] + fun runAnimationFor(parentId: String) { + val existingSettings = runningAnimations[parentId] existingSettings?.animator?.start() } - private fun setAnimationFor(item: ExpandableParentItem, state: ExpandableAnimationItemState) { - runningAnimations[item.getId()]?.animator?.cancel() // Cancel previous animation if it's exist + private fun setAnimationFor(parentId: String, state: ExpandableAnimationItemState) { + runningAnimations[parentId]?.animator?.cancel() // Cancel previous animation if it's exist val animator = ValueAnimator.ofFloat(state.animationFraction, 1f) .setDuration(animationSettings.duration) @@ -83,9 +83,9 @@ class ExpandableAnimator( state.animationFraction = it.animatedValue as Float recyclerView.invalidate() } // Invalidate recycler view to trigger onDraw in Item Decoration - animator.addListener(onEnd = { runningAnimations.remove(item.getId()) }) + animator.addListener(onEnd = { runningAnimations.remove(parentId) }) - runningAnimations[item.getId()] = RunningAnimation(state, animator) + runningAnimations[parentId] = RunningAnimation(state, animator) } fun cancelAnimations() { @@ -98,10 +98,10 @@ class ExpandableAnimator( val nextItem = items.getOrNull(position + 1) // If next item is not a parent item it means current item is fully expanded - return if (nextItem == null || nextItem !is ExpandableParentItem) { - ExpandableAnimationItemState(ExpandableAnimationItemState.Type.EXPANDING, 1f) - } else { + return if (nextItem == null || nextItem is ExpandableParentItem) { ExpandableAnimationItemState(ExpandableAnimationItemState.Type.COLLAPSING, 1f) + } else { + ExpandableAnimationItemState(ExpandableAnimationItemState.Type.EXPANDING, 1f) } } } diff --git a/common/src/main/res/drawable/bg_primary_list_item_corner_12.xml b/common/src/main/res/drawable/bg_primary_list_item_corner_12.xml new file mode 100644 index 0000000000..70b4025ffd --- /dev/null +++ b/common/src/main/res/drawable/bg_primary_list_item_corner_12.xml @@ -0,0 +1,12 @@ + + + + + + + + + \ No newline at end of file diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt index fbe1f7b756..152bf82014 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt @@ -17,6 +17,8 @@ class TokenAssetGroup( val itemsCount: Int ) { + val groupId: String = token.symbol.value + data class Token( val icon: String?, val symbol: TokenSymbol, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index 9f5f0a94df..2d8f474e71 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -9,9 +9,9 @@ import io.novafoundation.nova.feature_assets.domain.WalletInteractor import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.list.AssetsListInteractor import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork -import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_wallet_api.domain.model.Asset @@ -86,15 +86,17 @@ class RealAssetListMixin( when (viewMode) { AssetViewMode.NETWORKS -> walletInteractor.groupAssetsByNetwork(assets, externalBalances).mapGroupedAssetsToUi(currency) AssetViewMode.TOKENS -> walletInteractor.groupAssetsByToken(assets, externalBalances) - .mapValues { filterExpandedItems(it, expandedTokens) } - .mapGroupedAssetsToUi() + .mapGroupedAssetsToUi( + assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } + ) } }.distinctUntilChanged() .shareInBackground() override suspend fun switchViewMode() { - val assetViewMode = assetsViewModeFlow.first() + expandedTokenIdsFlow.value = emptySet() + val assetViewMode = assetsViewModeFlow.first() assetsListInteractor.setAssetViewMode(assetViewMode.switch()) } @@ -102,14 +104,19 @@ class RealAssetListMixin( expandedTokenIdsFlow.updateValue { it.toggle(tokenGroupUi.itemId) } } - private fun filterExpandedItems(entry: Map.Entry>, expandedTokens: Set): List { - val group = entry.key - val items = entry.value - - if (group.token.symbol.value in expandedTokens) { - return items + private fun filterTokens(groupId: String, assets: List, expandedGroups: Set): List { + if (groupId in expandedGroups) { + return filterIfSingleItem(assets) } return emptyList() } + + private fun filterIfSingleItem(assets: List): List { + return if (assets.size <= 1) { + emptyList() + } else { + assets + } + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt index 7303728d4f..e51ff9c9f1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt @@ -75,11 +75,10 @@ class AssetTokensDecoration( children: List ) { val expandingFraction = animationState.expandingFraction() - val flippedExpandingFraction = expandingFraction.flippedFraction() val parentBounds = parentBounds(parent) if (parentBounds != null) { - drawParentBlock(flippedExpandingFraction, parentBounds, canvas, expandingFraction) + drawParentBlock(parentBounds, canvas, expandingFraction) } // Don't draw children background if it's a single item @@ -116,13 +115,12 @@ class AssetTokensDecoration( } private fun drawParentBlock( - flippedExpandingFraction: Float, parentBounds: RectF, canvas: Canvas, expandingFraction: Float ) { val path = Path() - val bottomRadius = blockRadiusExpanded * flippedExpandingFraction + val bottomRadius = blockRadiusExpanded * expandingFraction.flippedFraction() parentBounds.toPath(path, topRadius = blockRadiusExpanded, bottomRadius = bottomRadius) paint.color = blockColor canvas.drawPath(path, paint) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt index 6bf7e18770..b2fcae1912 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt @@ -8,11 +8,9 @@ import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableIte import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator class AssetTokensItemAnimator( - adapter: ExpandableAdapter, settings: ExpandableAnimationSettings, expandableAnimator: ExpandableAnimator ) : ExpandableItemAnimator( - adapter, settings, expandableAnimator ) { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt index 50a8bd4f2f..724a539d23 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt @@ -20,17 +20,16 @@ fun GroupedList.mapGroupedAssetsToU balance: (TotalAndTransferableBalance) -> Amount = TotalAndTransferableBalance::total, ): List { return mapKeys { (assetGroup, _) -> mapAssetGroupToUi(assetGroup, currency, groupBalance) } - .mapValues { (group, assets) -> mapAssetsToAssetModels(group, assets, balance) } + .mapValues { (group, assets) -> mapAssetsToAssetModels(assets, balance) } .toListWithHeaders() .filterIsInstance() } private fun mapAssetsToAssetModels( - group: NetworkGroupUi, assets: List, balance: (TotalAndTransferableBalance) -> Amount ): List { - return assets.map { NetworkAssetUi(group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffchain))) } + return assets.map { NetworkAssetUi(mapAssetToAssetModel(it.asset, balance(it.balanceWithOffchain))) } } private fun mapAssetGroupToUi( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index 1e4f58a75b..c12cb3369f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -17,11 +17,15 @@ import io.novafoundation.nova.feature_currency_api.presentation.formatters.forma import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel fun GroupedList.mapGroupedAssetsToUi( + assetFilter: (groupId: String, List) -> List, groupBalance: (TokenAssetGroup) -> Amount = { it.groupBalance.total }, balance: (TotalAndTransferableBalance) -> Amount = TotalAndTransferableBalance::total, ): List { - return mapKeys { (group, _) -> mapAssetGroupToUi(group, groupBalance) } - .mapValues { (group, assets) -> mapAssetsToAssetModels(group, assets, balance) } + return mapKeys { (group, assets) -> mapAssetGroupToUi(group, assets, groupBalance) } + .mapValues { (group, assets) -> + val assetModels = mapAssetsToAssetModels(group, assets, balance) + assetFilter(group.itemId, assetModels) + } .toListWithHeaders() .filterIsInstance() } @@ -30,16 +34,19 @@ private fun mapAssetsToAssetModels( group: TokenGroupUi, assets: List, balance: (TotalAndTransferableBalance) -> Amount -): List { +): List { return assets.map { TokenAssetUi(group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } } + private fun mapAssetGroupToUi( assetGroup: TokenAssetGroup, + assets: List, groupBalance: (TokenAssetGroup) -> Amount ): TokenGroupUi { val balance = groupBalance(assetGroup) return TokenGroupUi( + itemId = assetGroup.groupId, tokenIcon = assetGroup.token.icon, rate = mapCoinRateChange(assetGroup.token.coinRate, assetGroup.token.currency), recentRateChange = assetGroup.token.coinRate?.recentRateChange.orZero().formatAsChange(), @@ -49,6 +56,20 @@ private fun mapAssetGroupToUi( balance = AmountModel( token = balance.amount.formatTokenAmount(), fiat = balance.fiat.formatAsCurrency(assetGroup.token.currency) - ) + ), + groupType = mapType(assetGroup, assets, groupBalance) ) } + +private fun mapType( + assetGroup: TokenAssetGroup, + assets: List, + groupBalance: (TokenAssetGroup) -> Amount +): TokenGroupUi.GroupType { + return if (assets.size == 1) { + val balance = groupBalance(assetGroup) + TokenGroupUi.GroupType.SingleItem(mapAssetToAssetModel(assets.first().asset, balance)) + } else { + TokenGroupUi.GroupType.Group + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index baa265a6d9..f927c42fca 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -75,7 +75,7 @@ class BalanceListFragment : val animator = ExpandableAnimator(balanceListAssets, animationSettings, assetsAdapter) balanceListAssets.addItemDecoration(AssetTokensDecoration(requireContext(), assetsAdapter, animator)) - balanceListAssets.itemAnimator = AssetTokensItemAnimator(assetsAdapter, animationSettings, animator) + balanceListAssets.itemAnimator = AssetTokensItemAnimator(animationSettings, animator) AssetNetworkDecoration.applyDefaultTo(balanceListAssets, assetsAdapter) @@ -147,7 +147,11 @@ class BalanceListFragment : } override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { - viewModel.assetListMixin.expandToken(tokenGroup) + if (tokenGroup.groupType is TokenGroupUi.GroupType.SingleItem) { + viewModel.assetClicked(tokenGroup.groupType.item) + } else { + viewModel.assetListMixin.expandToken(tokenGroup) + } } override fun totalBalanceClicked() { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt index 9a72281e17..3052088493 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt @@ -13,8 +13,8 @@ interface BalanceListRvItem : ExpandableBaseItem { } } -interface AssetGroupRvItem : BalanceListRvItem, ExpandableParentItem +interface AssetGroupRvItem : BalanceListRvItem -interface AssetRvItem : BalanceListRvItem, ExpandableChildItem { +interface AssetRvItem : BalanceListRvItem { val asset: AssetModel } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt index 2a17ab3ea6..5c086bec41 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt @@ -3,6 +3,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list.model.it import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.runtime.ext.fullId -data class NetworkAssetUi(override val groupId: String, override val asset: AssetModel) : AssetRvItem { - override val itemId: String = asset.token.configuration.fullId.toString() +data class NetworkAssetUi(override val asset: AssetModel) : AssetRvItem { + override val itemId: String = "network_" + asset.token.configuration.fullId.toString() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt index 2a55d738db..464ded3603 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt @@ -1,10 +1,11 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.feature_account_api.presenatation.chain.ChainUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.runtime.ext.fullId -data class TokenAssetUi(override val groupId: String, override val asset: AssetModel, val chain: ChainUi) : AssetRvItem { +data class TokenAssetUi(override val groupId: String, override val asset: AssetModel, val chain: ChainUi) : AssetRvItem, ExpandableChildItem { - override val itemId: String = asset.token.configuration.fullId.toString() + override val itemId: String = "token_" + asset.token.configuration.fullId.toString() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt index f788803d4e..c4c2b13df4 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt @@ -1,16 +1,26 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items import androidx.annotation.ColorRes +import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem +import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel data class TokenGroupUi( + override val itemId: String, val tokenIcon: String?, val rate: String, val recentRateChange: String, @ColorRes val rateChangeColorRes: Int, val tokenSymbol: String, val groupWithOneItem: Boolean, - val balance: AmountModel -) : AssetGroupRvItem { - override val itemId: String = tokenSymbol + val balance: AmountModel, + val groupType: GroupType +) : AssetGroupRvItem, ExpandableParentItem { + + + sealed interface GroupType { + object Group : GroupType + + data class SingleItem(val item: AssetModel) : GroupType + } } diff --git a/feature-assets/src/main/res/layout/item_token_asset_group.xml b/feature-assets/src/main/res/layout/item_token_asset_group.xml index f4031dd6b4..ec42da4f57 100644 --- a/feature-assets/src/main/res/layout/item_token_asset_group.xml +++ b/feature-assets/src/main/res/layout/item_token_asset_group.xml @@ -7,7 +7,7 @@ android:layout_height="64dp" android:layout_marginHorizontal="16dp" android:layout_weight="1" - android:background="@drawable/bg_primary_list_item" + android:background="@drawable/bg_primary_list_item_corner_12" tools:background="@color/block_background"> Date: Wed, 23 Oct 2024 04:33:20 +0200 Subject: [PATCH 15/78] Add prepare for animation flag --- .../expandable/ExpandableItemAnimator.kt | 36 +++++++++++++++---- .../balance/list/BalanceListFragment.kt | 3 ++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt index b3d440f4c1..e9e98ea48d 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt @@ -17,6 +17,8 @@ abstract class ExpandableItemAnimator( private val expandableAnimator: ExpandableAnimator ) : SimpleItemAnimator() { + private var preparedForAnimation = false + private val addAnimations = mutableMapOf>() // Parent item to children private val removeAnimations = mutableMapOf>() // Parent item to children private val moveAnimations = mutableListOf() @@ -33,12 +35,23 @@ abstract class ExpandableItemAnimator( supportsChangeAnimations = false } + /** + * Use this method before adapter.submitList() to prepare items for animation. + * Item animations will be skipped otherwise + */ + fun prepareForAnimation() { + preparedForAnimation = true + } + override fun animateAdd(holder: ViewHolder): Boolean { - if (holder !is ExpandableChildViewHolder || holder.expandableItem == null) { + val notPreparedForAnimation = !preparedForAnimation + val notExpandableChildItem = holder !is ExpandableChildViewHolder || holder.expandableItem == null + if (notPreparedForAnimation || notExpandableChildItem) { dispatchAddFinished(holder) return true } - val item = holder.expandableItem!! + + val item = (holder as ExpandableChildViewHolder).expandableItem!! // Reset move state helps clear translationY when animation is being to be canceled if (pendingMoveAnimations.contains(holder)) { @@ -62,11 +75,14 @@ abstract class ExpandableItemAnimator( } override fun animateRemove(holder: ViewHolder): Boolean { - if (holder !is ExpandableChildViewHolder || holder.expandableItem == null) { + val notPreparedForAnimation = !preparedForAnimation + val notExpandableChildItem = holder !is ExpandableChildViewHolder || holder.expandableItem == null + if (notPreparedForAnimation || notExpandableChildItem) { dispatchRemoveFinished(holder) - return false + return true } - val item = holder.expandableItem!! + + val item = (holder as ExpandableChildViewHolder).expandableItem!! // Reset move state helps clear translationY when animation is being to be canceled if (pendingMoveAnimations.contains(holder)) { @@ -90,9 +106,10 @@ abstract class ExpandableItemAnimator( } override fun animateMove(holder: ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int): Boolean { - if (holder !is ExpandableBaseViewHolder<*>) { + val notPreparedForAnimation = !preparedForAnimation + if (notPreparedForAnimation || holder !is ExpandableBaseViewHolder<*>) { dispatchMoveFinished(holder) - return false + return true } // Reset add state helps clear alpha and scale when animation is being to be canceled @@ -142,6 +159,11 @@ abstract class ExpandableItemAnimator( } pendingMoveAnimations.addAll(animatingViewHolders) + + // Set prepare for animation = false to return to skipping animations + if (pendingAddAnimations.isNotEmpty() || pendingRemoveAnimations.isNotEmpty() || pendingMoveAnimations.isNotEmpty()) { + preparedForAnimation = false + } } private fun runExpandableAnimationFor( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index f927c42fca..af78541b2d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -150,6 +150,9 @@ class BalanceListFragment : if (tokenGroup.groupType is TokenGroupUi.GroupType.SingleItem) { viewModel.assetClicked(tokenGroup.groupType.item) } else { + val itemAnimator = balanceListAssets.itemAnimator as AssetTokensItemAnimator + itemAnimator.prepareForAnimation() + viewModel.assetListMixin.expandToken(tokenGroup) } } From 7cef9e03a1ae76a04d036791eae9ac8194d903da Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 23 Oct 2024 04:34:41 +0200 Subject: [PATCH 16/78] Run ktlint --- .../presentation/balance/common/AssetListMixin.kt | 1 - .../presentation/balance/common/AssetTokensItemAnimator.kt | 1 - .../presentation/balance/common/mappers/TokenAssetMappers.kt | 1 - .../presentation/balance/list/model/items/AssetRvItem.kt | 2 -- .../presentation/balance/list/model/items/TokenGroupUi.kt | 1 - 5 files changed, 6 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index 2d8f474e71..2840c2d3fc 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -8,7 +8,6 @@ import io.novafoundation.nova.common.utils.updateValue import io.novafoundation.nova.feature_assets.domain.WalletInteractor import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.list.AssetsListInteractor -import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt index b2fcae1912..e4f1894c2e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt @@ -2,7 +2,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common import android.view.ViewPropertyAnimator import androidx.recyclerview.widget.RecyclerView -import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAdapter import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAnimationSettings import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableItemAnimator import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index c12cb3369f..2dc0a4819f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -38,7 +38,6 @@ private fun mapAssetsToAssetModels( return assets.map { TokenAssetUi(group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } } - private fun mapAssetGroupToUi( assetGroup: TokenAssetGroup, assets: List, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt index 3052088493..8801d80e9a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/AssetRvItem.kt @@ -1,8 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem -import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem -import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem import io.novafoundation.nova.feature_assets.presentation.model.AssetModel interface BalanceListRvItem : ExpandableBaseItem { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt index c4c2b13df4..357bad4011 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt @@ -17,7 +17,6 @@ data class TokenGroupUi( val groupType: GroupType ) : AssetGroupRvItem, ExpandableParentItem { - sealed interface GroupType { object Group : GroupType From 0b42627509509caad8b732ee03d96544441a5124 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 23 Oct 2024 13:04:08 +0200 Subject: [PATCH 17/78] Update ExpandableItemAnimator.kt --- .../utils/recyclerView/expandable/ExpandableItemAnimator.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt index e9e98ea48d..daab2f4150 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt @@ -48,7 +48,7 @@ abstract class ExpandableItemAnimator( val notExpandableChildItem = holder !is ExpandableChildViewHolder || holder.expandableItem == null if (notPreparedForAnimation || notExpandableChildItem) { dispatchAddFinished(holder) - return true + return false } val item = (holder as ExpandableChildViewHolder).expandableItem!! @@ -79,7 +79,7 @@ abstract class ExpandableItemAnimator( val notExpandableChildItem = holder !is ExpandableChildViewHolder || holder.expandableItem == null if (notPreparedForAnimation || notExpandableChildItem) { dispatchRemoveFinished(holder) - return true + return false } val item = (holder as ExpandableChildViewHolder).expandableItem!! @@ -109,7 +109,7 @@ abstract class ExpandableItemAnimator( val notPreparedForAnimation = !preparedForAnimation if (notPreparedForAnimation || holder !is ExpandableBaseViewHolder<*>) { dispatchMoveFinished(holder) - return true + return false } // Reset add state helps clear alpha and scale when animation is being to be canceled From 1c3c27b710308fab44ba82d7dabedb4fbb207f7a Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 24 Oct 2024 12:06:11 +0200 Subject: [PATCH 18/78] Asset Network Flow. Buy flow --- .../nova/app/root/navigation/Navigator.kt | 18 ++ .../main/res/navigation/main_nav_graph.xml | 19 +- .../nova/common/utils/KEY_PAYLOAD.kt | 36 ++++ .../bg_primary_list_item_corner_12_solid.xml | 19 ++ common/src/main/res/values/strings.xml | 2 + .../di/AssetsFeatureComponent.kt | 5 +- .../feature_assets/di/AssetsFeatureModule.kt | 15 +- .../assets/models/AssetFlowSearchResult.kt | 19 ++ .../assets/search/AssetSearchInteractor.kt | 175 +++++++++++++----- .../networks/AssetNetworksInteractor.kt | 145 +++++++++++++++ .../presentation/AssetsRouter.kt | 9 + .../balance/common/AssetTokensDecoration.kt | 2 +- .../AssetBaseDecoration.kt} | 33 ++-- .../AssetDecorationPreferences.kt | 81 ++++++++ .../common/mappers/TokenAssetMappers.kt | 22 +-- .../balance/list/BalanceListFragment.kt | 6 +- .../balance/list/model/items/TokenGroupUi.kt | 2 +- .../balance/search/AssetSearchFragment.kt | 6 +- .../flow/{ => asset}/AssetBuyFlowFragment.kt | 8 +- .../flow/{ => asset}/AssetBuyFlowViewModel.kt | 15 +- .../{ => asset}/di/AssetBuyFlowComponent.kt | 4 +- .../flow/{ => asset}/di/AssetBuyFlowModule.kt | 4 +- .../flow/network/NetworkBuyFlowFragment.kt | 30 +++ .../flow/network/NetworkBuyFlowViewModel.kt | 62 +++++++ .../network/di/NetworkBuyFlowComponent.kt | 29 +++ .../flow/network/di/NetworkBuyFlowModule.kt | 56 ++++++ .../flow/{ => asset}/AssetFlowFragment.kt | 36 +++- .../flow/{ => asset}/AssetFlowViewModel.kt | 45 +++-- .../flow/network/NetworkFlowAdapter.kt | 61 ++++++ .../flow/network/NetworkFlowFragment.kt | 88 +++++++++ .../flow/network/NetworkFlowPayload.kt | 10 + .../flow/network/NetworkFlowViewModel.kt | 77 ++++++++ .../flow/network/model/NetworkFlowRvItem.kt | 11 ++ .../receive/flow/AssetReceiveFlowFragment.kt | 2 +- .../receive/flow/AssetReceiveFlowViewModel.kt | 13 +- .../send/flow/AssetSendFlowFragment.kt | 2 +- .../send/flow/AssetSendFlowViewModel.kt | 19 +- .../swap/AssetSwapFlowFragment.kt | 2 +- .../swap/AssetSwapFlowViewModel.kt | 19 +- .../main/res/layout/fragment_network_flow.xml | 28 +++ .../src/main/res/layout/item_network_flow.xml | 68 +++++++ 41 files changed, 1168 insertions(+), 135 deletions(-) create mode 100644 common/src/main/java/io/novafoundation/nova/common/utils/KEY_PAYLOAD.kt create mode 100644 common/src/main/res/drawable/bg_primary_list_item_corner_12_solid.xml create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/{AssetNetworkDecoration.kt => baseDecoration/AssetBaseDecoration.kt} (82%) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/baseDecoration/AssetDecorationPreferences.kt rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/{ => asset}/AssetBuyFlowFragment.kt (84%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/{ => asset}/AssetBuyFlowViewModel.kt (74%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/{ => asset}/di/AssetBuyFlowComponent.kt (93%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/{ => asset}/di/AssetBuyFlowModule.kt (98%) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowComponent.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowModule.kt rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/{ => asset}/AssetFlowFragment.kt (72%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/{ => asset}/AssetFlowViewModel.kt (68%) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowAdapter.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowPayload.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/model/NetworkFlowRvItem.kt create mode 100644 feature-assets/src/main/res/layout/fragment_network_flow.xml create mode 100644 feature-assets/src/main/res/layout/item_network_flow.xml diff --git a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt index 1c4b392e58..b8cd08b0b6 100644 --- a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt +++ b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt @@ -52,6 +52,8 @@ import io.novafoundation.nova.feature_account_impl.presentation.startCreateWalle import io.novafoundation.nova.feature_account_impl.presentation.watchOnly.change.ChangeWatchAccountFragment import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.detail.BalanceDetailFragment +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.model.OperationParcelizeModel import io.novafoundation.nova.feature_assets.presentation.receive.ReceiveFragment import io.novafoundation.nova.feature_assets.presentation.send.TransferDraft @@ -383,6 +385,22 @@ class Navigator( navController?.navigate(R.id.action_close_send_flow) } + override fun openSendNetworks(networkFlowPayload: NetworkFlowPayload) { + TODO("Not yet implemented") + } + + override fun openReceiveNetworks(networkFlowPayload: NetworkFlowPayload) { + TODO("Not yet implemented") + } + + override fun openSwapNetworks(networkFlowPayload: NetworkFlowPayload) { + TODO("Not yet implemented") + } + + override fun openBuyNetworks(networkFlowPayload: NetworkFlowPayload) { + navController?.navigate(R.id.action_buyFlow_to_buyFlowNetwork, NetworkFlowFragment.createPayload(networkFlowPayload)) + } + override fun openSwapFlow() { val payload = SwapFlowPayload.InitialSelecting navController?.navigate(R.id.action_mainFragment_to_swapFlow, AssetSwapFlowFragment.getBundle(payload)) diff --git a/app/src/main/res/navigation/main_nav_graph.xml b/app/src/main/res/navigation/main_nav_graph.xml index 7c8b340124..5d3114f58e 100644 --- a/app/src/main/res/navigation/main_nav_graph.xml +++ b/app/src/main/res/navigation/main_nav_graph.xml @@ -893,8 +893,23 @@ + android:name="io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowFragment" + android:label="AssetBuyFlowFragment"> + + + + + + { + + fun createPayload(payload: T): Bundle +} + +class FragmentPayloadCreator : PayloadCreator { + + override fun createPayload(payload: T): Bundle { + return Bundle().apply { + putParcelable(KEY_PAYLOAD, payload) + } + } +} + +interface PayloadHolder { + + val payload: T +} + +interface FragmentPayloadHolder : PayloadHolder { + + override val payload: T + get() { + require(this is Fragment) + return requireArguments().getParcelable(KEY_PAYLOAD)!! + } + +} diff --git a/common/src/main/res/drawable/bg_primary_list_item_corner_12_solid.xml b/common/src/main/res/drawable/bg_primary_list_item_corner_12_solid.xml new file mode 100644 index 0000000000..ca2c3db466 --- /dev/null +++ b/common/src/main/res/drawable/bg_primary_list_item_corner_12_solid.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index 6659575291..a5b36727bd 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -1,6 +1,8 @@ + Select network for buying %s + Tokens Networks diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt index a78fe94634..e886670fa8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt @@ -12,7 +12,8 @@ import io.novafoundation.nova.feature_assets.presentation.balance.detail.di.Bala import io.novafoundation.nova.feature_assets.presentation.balance.list.di.BalanceListComponent import io.novafoundation.nova.feature_assets.presentation.balance.list.view.GoToNftsView import io.novafoundation.nova.feature_assets.presentation.balance.search.di.AssetSearchComponent -import io.novafoundation.nova.feature_assets.presentation.buy.flow.di.AssetBuyFlowComponent +import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.di.AssetBuyFlowComponent +import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.di.NetworkBuyFlowComponent import io.novafoundation.nova.feature_assets.presentation.receive.di.ReceiveComponent import io.novafoundation.nova.feature_assets.presentation.receive.flow.di.AssetReceiveFlowComponent import io.novafoundation.nova.feature_assets.presentation.send.amount.di.SelectSendComponent @@ -91,6 +92,8 @@ interface AssetsFeatureComponent : AssetsFeatureApi { fun buyFlowComponent(): AssetBuyFlowComponent.Factory + fun networkBuyFlowComponent(): NetworkBuyFlowComponent.Factory + fun inject(view: GoToNftsView) @Component.Factory diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt index 3c99128536..6c30ec902a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_assets.di import dagger.Module import dagger.Provides import io.novafoundation.nova.common.data.memory.ComputationalCache +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.FeatureScope import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin @@ -24,6 +25,7 @@ import io.novafoundation.nova.feature_assets.domain.WalletInteractorImpl import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.RealExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.transaction.filter.HistoryFiltersProviderFactory import io.novafoundation.nova.feature_currency_api.domain.interfaces.CurrencyRepository @@ -56,9 +58,18 @@ class AssetsFeatureModule { walletRepository: WalletRepository, accountRepository: AccountRepository, chainRegistry: ChainRegistry, - assetSourceRegistry: AssetSourceRegistry, + swapService: SwapService, + assetsViewModeRepository: AssetsViewModeRepository + ) = AssetSearchInteractor(walletRepository, accountRepository, chainRegistry, swapService, assetsViewModeRepository) + + @Provides + @FeatureScope + fun provideAssetNetworksInteractor( + walletRepository: WalletRepository, + accountRepository: AccountRepository, + chainRegistry: ChainRegistry, swapService: SwapService - ) = AssetSearchInteractor(walletRepository, accountRepository, chainRegistry, assetSourceRegistry, swapService) + ) = AssetNetworksInteractor(walletRepository, accountRepository, chainRegistry, swapService) @Provides @FeatureScope diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt new file mode 100644 index 0000000000..08a6c754bc --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt @@ -0,0 +1,19 @@ +package io.novafoundation.nova.feature_assets.domain.assets.models + +import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup + +sealed interface AssetFlowSearchResult { + + class ByNetworks(val assets: Map>) : AssetFlowSearchResult + + class ByTokens(val tokens: List) : AssetFlowSearchResult +} + +fun AssetFlowSearchResult.toList(): List { + return when (this) { + is AssetFlowSearchResult.ByNetworks -> assets.keys.toList() + is AssetFlowSearchResult.ByTokens -> tokens + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt index e46ffce1a8..5fd2e0f79d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt @@ -1,15 +1,22 @@ package io.novafoundation.nova.feature_assets.domain.assets.search +import io.novafoundation.nova.common.data.model.AssetViewMode +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.utils.flowOfAll import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.domain.common.getAssetBaseComparator import io.novafoundation.nova.feature_assets.domain.common.getAssetGroupBaseComparator +import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetBaseComparator +import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetGroupBaseComparator import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByNetwork +import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByToken import io.novafoundation.nova.feature_assets.domain.common.searchTokens import io.novafoundation.nova.feature_swap_api.domain.swap.SwapService -import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.AssetSourceRegistry import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletRepository import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance @@ -34,28 +41,52 @@ class AssetSearchInteractor( private val walletRepository: WalletRepository, private val accountRepository: AccountRepository, private val chainRegistry: ChainRegistry, - private val assetSourceRegistry: AssetSourceRegistry, - private val swapService: SwapService + private val swapService: SwapService, + private val assetsViewModeRepository: AssetsViewModeRepository ) { fun buyAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow>> { - return searchAssetsInternalFlow(queryFlow, externalBalancesFlow) { - it.token.configuration.buyProviders.isNotEmpty() + ): Flow { + val filter = { asset: Asset -> asset.token.configuration.buyProviders.isNotEmpty() } + + return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> + when (viewMode) { + AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = filter) + .map { AssetFlowSearchResult.ByNetworks(it) } + + AssetViewMode.TOKENS -> searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = filter) + .map { AssetFlowSearchResult.ByTokens(it.keys.toList()) } + } } } fun sendAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow>> { - val groupComparator = getAssetGroupBaseComparator { it.groupTransferableBalanceFiat } - val assetsComparator = getAssetBaseComparator { it.balanceWithOffchain.transferable.fiat } - - return searchAssetsInternalFlow(queryFlow, externalBalancesFlow, groupComparator, assetsComparator) { asset -> - asset.transferableInPlanks.isPositive() + ): Flow { + val filter = { asset: Asset -> asset.transferableInPlanks.isPositive() } + + return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> + when (viewMode) { + AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow( + queryFlow, + externalBalancesFlow, + assetGroupComparator = getAssetGroupBaseComparator { it.groupTransferableBalanceFiat }, + assetsComparator = getAssetBaseComparator { it.balanceWithOffchain.transferable.fiat }, + filter = filter + ).map { AssetFlowSearchResult.ByNetworks(it) } + + AssetViewMode.TOKENS -> searchAssetsByTokensInternalFlow( + queryFlow, + externalBalancesFlow, + assetGroupComparator = getTokenAssetGroupBaseComparator { it.groupBalance.transferable.fiat }, + assetsComparator = getTokenAssetBaseComparator { it.balanceWithOffChain.transferable.fiat }, + filter = filter + ) + .map { AssetFlowSearchResult.ByTokens(it.keys.toList()) } + } } } @@ -64,7 +95,7 @@ class AssetSearchInteractor( queryFlow: Flow, externalBalancesFlow: Flow>, coroutineScope: CoroutineScope - ): Flow>> { + ): Flow { val filterFlow = getAvailableSwapAssets(forAsset, coroutineScope).map { availableAssetsForSwap -> val filter: AssetSearchFilter = { asset -> val chainAsset = asset.token.configuration @@ -75,65 +106,99 @@ class AssetSearchInteractor( filter } - return searchAssetsInternalFlow(queryFlow, externalBalancesFlow, filterFlow = filterFlow) + return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> + when (viewMode) { + AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filterFlow = filterFlow) + .map { AssetFlowSearchResult.ByNetworks(it) } + + AssetViewMode.TOKENS -> searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filterFlow = filterFlow) + .map { AssetFlowSearchResult.ByTokens(it.keys.toList()) } + } + } } - fun searchAssetsFlow( + fun searchReceiveAssetsFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow>> { - return searchAssetsInternalFlow(queryFlow, externalBalancesFlow, filter = null) - } - - private fun getAvailableSwapAssets(asset: FullChainAssetId?, coroutineScope: CoroutineScope): Flow> { - return flowOfAll { - val chainAsset = asset?.let { chainRegistry.asset(it) } - - if (chainAsset == null) { - swapService.assetsAvailableForSwap(coroutineScope) - } else { - swapService.availableSwapDirectionsFor(chainAsset, coroutineScope) + ): Flow { + return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> + when (viewMode) { + AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = null) + .map { AssetFlowSearchResult.ByNetworks(it) } + + AssetViewMode.TOKENS -> searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = null) + .map { AssetFlowSearchResult.ByTokens(it.keys.toList()) } } } } - private fun searchAssetsInternalFlow( + fun searchAssetsFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - assetGroupComparator: Comparator = getAssetGroupBaseComparator(), - assetsComparator: Comparator = getAssetBaseComparator(), - filter: AssetSearchFilter?, ): Flow>> { - val filterFlow = flowOf(filter) - - return searchAssetsInternalFlow(queryFlow, externalBalancesFlow, assetGroupComparator, assetsComparator, filterFlow) + return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = null) } - private fun searchAssetsInternalFlow( + fun searchAssetsByNetworksInternalFlow( queryFlow: Flow, externalBalancesFlow: Flow>, assetGroupComparator: Comparator = getAssetGroupBaseComparator(), assetsComparator: Comparator = getAssetBaseComparator(), filterFlow: Flow, ): Flow>> { - var assetsFlow = accountRepository.selectedMetaAccountFlow() + val assetsFlow = filteredAssetFlow(filterFlow) + + val aggregatedExternalBalances = externalBalancesFlow.map { it.aggregatedBalanceByAsset() } + + return combine(assetsFlow, aggregatedExternalBalances, queryFlow) { assets, externalBalances, query -> + val chainsById = chainRegistry.enabledChainById() + val filtered = assets.filterBy(query, chainsById) + + groupAndSortAssetsByNetwork(filtered, externalBalances, chainsById, assetGroupComparator, assetsComparator) + } + } + + fun searchAssetsByTokensInternalFlow( + queryFlow: Flow, + externalBalancesFlow: Flow>, + assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), + assetsComparator: Comparator = getTokenAssetBaseComparator(), + filterFlow: Flow, + ): Flow>> { + val assetsFlow = filteredAssetFlow(filterFlow) + + val aggregatedExternalBalances = externalBalancesFlow.map { it.aggregatedBalanceByAsset() } + + return combine(assetsFlow, aggregatedExternalBalances, queryFlow) { assets, externalBalances, query -> + val chainsById = chainRegistry.enabledChainById() + val filtered = assets.filterBy(query, chainsById) + + groupAndSortAssetsByToken(filtered, externalBalances, chainsById, assetGroupComparator, assetsComparator) + } + } + + private fun filteredAssetFlow(filterFlow: Flow): Flow> { + val assetsFlow = accountRepository.selectedMetaAccountFlow() .flatMapLatest { walletRepository.syncedAssetsFlow(it.id) } - assetsFlow = combine(assetsFlow, filterFlow) { assets, filter -> + return combine(assetsFlow, filterFlow) { assets, filter -> if (filter == null) { assets } else { assets.filter { filter(it) } } } + } - val aggregatedExternalBalances = externalBalancesFlow.map { it.aggregatedBalanceByAsset() } - - return combine(assetsFlow, aggregatedExternalBalances, queryFlow) { assets, externalBalances, query -> - val chainsById = chainRegistry.enabledChainById() - val filtered = assets.filterBy(query, chainsById) + private fun getAvailableSwapAssets(asset: FullChainAssetId?, coroutineScope: CoroutineScope): Flow> { + return flowOfAll { + val chainAsset = asset?.let { chainRegistry.asset(it) } - groupAndSortAssetsByNetwork(filtered, externalBalances, chainsById, assetGroupComparator, assetsComparator) + if (chainAsset == null) { + swapService.assetsAvailableForSwap(coroutineScope) + } else { + swapService.availableSwapDirectionsFor(chainAsset, coroutineScope) + } } } @@ -146,3 +211,27 @@ class AssetSearchInteractor( ) } } + +private fun AssetSearchInteractor.searchAssetsByNetworksInternalFlow( + queryFlow: Flow, + externalBalancesFlow: Flow>, + assetGroupComparator: Comparator = getAssetGroupBaseComparator(), + assetsComparator: Comparator = getAssetBaseComparator(), + filter: AssetSearchFilter?, +): Flow>> { + val filterFlow = flowOf(filter) + + return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, assetGroupComparator, assetsComparator, filterFlow) +} + +private fun AssetSearchInteractor.searchAssetsByTokensInternalFlow( + queryFlow: Flow, + externalBalancesFlow: Flow>, + assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), + assetsComparator: Comparator = getTokenAssetBaseComparator(), + filter: AssetSearchFilter?, +): Flow>> { + val filterFlow = flowOf(filter) + + return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, assetGroupComparator, assetsComparator, filterFlow) +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt new file mode 100644 index 0000000000..2d0181d010 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt @@ -0,0 +1,145 @@ +package io.novafoundation.nova.feature_assets.domain.networks + +import io.novafoundation.nova.common.utils.TokenSymbol +import io.novafoundation.nova.common.utils.filterList +import io.novafoundation.nova.common.utils.flowOfAll +import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup +import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetBaseComparator +import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetGroupBaseComparator +import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByToken +import io.novafoundation.nova.feature_swap_api.domain.swap.SwapService +import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletRepository +import io.novafoundation.nova.feature_wallet_api.domain.model.Asset +import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance +import io.novafoundation.nova.feature_wallet_api.domain.model.aggregatedBalanceByAsset +import io.novafoundation.nova.runtime.ext.fullId +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry +import io.novafoundation.nova.runtime.multiNetwork.asset +import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId +import io.novafoundation.nova.runtime.multiNetwork.enabledChainById +import io.novasama.substrate_sdk_android.hash.isPositive +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map + +private typealias AssetFilter = suspend (Asset) -> Boolean + +class AssetNetworksInteractor( + private val walletRepository: WalletRepository, + private val accountRepository: AccountRepository, + private val chainRegistry: ChainRegistry, + private val swapService: SwapService +) { + + fun buyAssetFlow( + tokenSymbol: TokenSymbol, + externalBalancesFlow: Flow>, + ): Flow> { + val filter = { asset: Asset -> asset.token.configuration.buyProviders.isNotEmpty() } + + return searchAssetsByTokenSymbolInternalFlow(tokenSymbol, externalBalancesFlow, filter = filter) + } + + fun sendAssetFlow( + tokenSymbol: TokenSymbol, + externalBalancesFlow: Flow>, + ): Flow> { + val filter = { asset: Asset -> asset.transferableInPlanks.isPositive() } + + return searchAssetsByTokenSymbolInternalFlow( + tokenSymbol, + externalBalancesFlow, + assetGroupComparator = getTokenAssetGroupBaseComparator { it.groupBalance.transferable.fiat }, + assetsComparator = getTokenAssetBaseComparator { it.balanceWithOffChain.transferable.fiat }, + filter = filter + ) + } + + fun swapAssetsFlow( + forAsset: FullChainAssetId?, + tokenSymbol: TokenSymbol, + externalBalancesFlow: Flow>, + coroutineScope: CoroutineScope + ): Flow> { + val filterFlow = getAvailableSwapAssets(forAsset, coroutineScope).map { availableAssetsForSwap -> + val filter: AssetFilter = { asset -> + val chainAsset = asset.token.configuration + + chainAsset.fullId in availableAssetsForSwap + } + + filter + } + + return searchAssetsByTokenSymbolInternalFlow(tokenSymbol, externalBalancesFlow, filterFlow = filterFlow) + } + + fun receiveAssetsFlow( + tokenSymbol: TokenSymbol, + externalBalancesFlow: Flow>, + ): Flow> { + return searchAssetsByTokenSymbolInternalFlow(tokenSymbol, externalBalancesFlow, filter = null) + } + + fun searchAssetsByTokenSymbolInternalFlow( + tokenSymbol: TokenSymbol, + externalBalancesFlow: Flow>, + assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), + assetsComparator: Comparator = getTokenAssetBaseComparator(), + filterFlow: Flow, + ): Flow> { + val assetsFlow = filteredAssetFlow(filterFlow) + .filterList { it.token.configuration.symbol == tokenSymbol } + + val aggregatedExternalBalances = externalBalancesFlow.map { it.aggregatedBalanceByAsset() } + + return combine(assetsFlow, aggregatedExternalBalances) { assets, externalBalances -> + val chainsById = chainRegistry.enabledChainById() + + groupAndSortAssetsByToken(assets, externalBalances, chainsById, assetGroupComparator, assetsComparator) + .flatMap { it.value } + } + } + + private fun filteredAssetFlow(filterFlow: Flow): Flow> { + val assetsFlow = accountRepository.selectedMetaAccountFlow() + .flatMapLatest { walletRepository.syncedAssetsFlow(it.id) } + + return combine(assetsFlow, filterFlow) { assets, filter -> + if (filter == null) { + assets + } else { + assets.filter { filter(it) } + } + } + } + + private fun getAvailableSwapAssets(asset: FullChainAssetId?, coroutineScope: CoroutineScope): Flow> { + return flowOfAll { + val chainAsset = asset?.let { chainRegistry.asset(it) } + + if (chainAsset == null) { + swapService.assetsAvailableForSwap(coroutineScope) + } else { + swapService.availableSwapDirectionsFor(chainAsset, coroutineScope) + } + } + } +} + +private fun AssetNetworksInteractor.searchAssetsByTokenSymbolInternalFlow( + tokenSymbol: TokenSymbol, + externalBalancesFlow: Flow>, + assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), + assetsComparator: Comparator = getTokenAssetBaseComparator(), + filter: AssetFilter?, +): Flow> { + val filterFlow = flowOf(filter) + + return searchAssetsByTokenSymbolInternalFlow(tokenSymbol, externalBalancesFlow, assetGroupComparator, assetsComparator, filterFlow) +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt index c811cb81fb..e2a19334a1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt @@ -1,6 +1,7 @@ package io.novafoundation.nova.feature_assets.presentation import android.os.Bundle +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.model.OperationParcelizeModel import io.novafoundation.nova.feature_assets.presentation.send.TransferDraft import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload @@ -73,4 +74,12 @@ interface AssetsRouter { fun openStaking() fun closeSendFlow() + + fun openSendNetworks(networkFlowPayload: NetworkFlowPayload) + + fun openReceiveNetworks(networkFlowPayload: NetworkFlowPayload) + + fun openSwapNetworks(networkFlowPayload: NetworkFlowPayload) + + fun openBuyNetworks(networkFlowPayload: NetworkFlowPayload) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt index e51ff9c9f1..595937b295 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt @@ -82,7 +82,7 @@ class AssetTokensDecoration( } // Don't draw children background if it's a single item - if (parentItem is TokenGroupUi && parentItem.groupWithOneItem) return + if (parentItem is TokenGroupUi && parentItem.singleItemGroup) return val childrenBlockBounds = getChildrenBlockBounds(animationState, recyclerView, parent, children) drawChildrenBlock(expandingFraction, childrenBlockBounds, canvas) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetNetworkDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/baseDecoration/AssetBaseDecoration.kt similarity index 82% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetNetworkDecoration.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/baseDecoration/AssetBaseDecoration.kt index e70ef66089..4365c3460c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetNetworkDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/baseDecoration/AssetBaseDecoration.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.balance.common +package io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration import android.content.Context import android.graphics.Canvas @@ -12,8 +12,6 @@ import io.novafoundation.nova.common.utils.dp import io.novafoundation.nova.common.view.shape.addRipple import io.novafoundation.nova.common.view.shape.getRoundedCornerDrawable import io.novafoundation.nova.feature_assets.R -import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetGroupViewHolder -import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetViewHolder import kotlin.math.roundToInt /** @@ -21,17 +19,16 @@ import kotlin.math.roundToInt * The issue is that this decoration does not currently support partial list updates and assumes it will be iterated over whole list * TODO update decoration to not require this invalidation */ -class AssetNetworkDecoration( +class AssetBaseDecoration( private val background: Drawable, private val assetsAdapter: ListAdapter<*, *>, context: Context, + private val preferences: AssetDecorationPreferences ) : RecyclerView.ItemDecoration() { companion object; private val bounds = Rect() - private val groupOuterSpacing = 8.dp(context) - private val groupInnerSpacing = 8.dp(context) // used to hide rounded corners for the last group to simulate effect of not-closed group private val finalGroupExtraPadding = 20.dp(context) @@ -61,7 +58,7 @@ class AssetNetworkDecoration( parent.getDecoratedBoundsWithMargins(view, bounds) bounds.set(view.left, bounds.top, view.right, bounds.bottom) - val groupBottom = bounds.bottom + view.translationY.roundToInt() - groupOuterSpacing + val groupBottom = bounds.bottom + view.translationY.roundToInt() - preferences.outerGroupPadding(viewHolder) background.setBounds(bounds.left, groupTop!!, bounds.right, groupBottom) background.draw(c) @@ -99,7 +96,11 @@ class AssetNetworkDecoration( val nextType = assetsAdapter.getItemViewTypeOrNull(adapterPosition + 1) - val bottom = if (isFinalItemInGroup(nextType)) groupInnerSpacing + groupOuterSpacing else 0 + val bottom = if (isFinalItemInGroup(nextType)) { + preferences.outerGroupPadding(viewHolder) + preferences.innerGroupPadding(viewHolder) + } else { + 0 + } outRect.set(0, 0, 0, bottom) } @@ -111,28 +112,30 @@ class AssetNetworkDecoration( } private fun isFinalItemInGroup(nextType: Int?): Boolean { - return nextType == TYPE_NETWORK_GROUP || nextType == null + return nextType == null || preferences.isGroupItem(nextType) } private fun shouldSkip(viewHolder: RecyclerView.ViewHolder): Boolean { - val isNetworkViewHolder = viewHolder is NetworkAssetViewHolder || - viewHolder is NetworkAssetGroupViewHolder + val noPosition = viewHolder.bindingAdapterPosition == RecyclerView.NO_POSITION + val unsupportedViewHolder = !preferences.shouldUseViewHolder(viewHolder) - return viewHolder.bindingAdapterPosition == RecyclerView.NO_POSITION || !isNetworkViewHolder + return noPosition || unsupportedViewHolder } } -fun AssetNetworkDecoration.Companion.applyDefaultTo( +fun AssetBaseDecoration.Companion.applyDefaultTo( recyclerView: RecyclerView, - adapter: ListAdapter<*, *> + adapter: ListAdapter<*, *>, + preferences: AssetDecorationPreferences = NetworkAssetDecorationPreferences() ) { val groupBackground = with(recyclerView.context) { addRipple(getRoundedCornerDrawable(R.color.block_background)) } - val decoration = AssetNetworkDecoration( + val decoration = AssetBaseDecoration( background = groupBackground, assetsAdapter = adapter, context = recyclerView.context, + preferences = preferences ) recyclerView.addItemDecoration(decoration) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/baseDecoration/AssetDecorationPreferences.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/baseDecoration/AssetDecorationPreferences.kt new file mode 100644 index 0000000000..8f8ae0f338 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/baseDecoration/AssetDecorationPreferences.kt @@ -0,0 +1,81 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration + +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import io.novafoundation.nova.common.utils.dp +import io.novafoundation.nova.feature_assets.presentation.balance.common.TYPE_NETWORK_GROUP +import io.novafoundation.nova.feature_assets.presentation.balance.common.TYPE_TOKEN_GROUP +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetGroupViewHolder +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.NetworkAssetViewHolder +import io.novafoundation.nova.feature_assets.presentation.balance.common.holders.TokenAssetGroupViewHolder + +interface AssetDecorationPreferences { + + fun innerGroupPadding(viewHolder: ViewHolder): Int + + fun outerGroupPadding(viewHolder: ViewHolder): Int + + fun isGroupItem(viewType: Int): Boolean + + fun shouldUseViewHolder(viewHolder: ViewHolder): Boolean +} + +class NetworkAssetDecorationPreferences : AssetDecorationPreferences { + + override fun innerGroupPadding(viewHolder: ViewHolder): Int { + return 8.dp(viewHolder.itemView.context) + } + + override fun outerGroupPadding(viewHolder: ViewHolder): Int { + return 8.dp(viewHolder.itemView.context) + } + + override fun isGroupItem(viewType: Int): Boolean { + return viewType == TYPE_NETWORK_GROUP + } + + override fun shouldUseViewHolder(viewHolder: ViewHolder): Boolean { + return viewHolder is NetworkAssetViewHolder || + viewHolder is NetworkAssetGroupViewHolder + } +} + +class TokenAssetGroupDecorationPreferences : AssetDecorationPreferences { + + override fun innerGroupPadding(viewHolder: ViewHolder): Int { + return 0 + } + + override fun outerGroupPadding(viewHolder: ViewHolder): Int { + return 8.dp(viewHolder.itemView.context) + } + + override fun isGroupItem(viewType: Int): Boolean { + return viewType == TYPE_TOKEN_GROUP + } + + override fun shouldUseViewHolder(viewHolder: ViewHolder): Boolean { + return viewHolder is TokenAssetGroupViewHolder + } +} + +class CompoundAssetDecorationPreferences(private vararg val preferences: AssetDecorationPreferences) : AssetDecorationPreferences { + + override fun innerGroupPadding(viewHolder: ViewHolder): Int { + val firstPreferences = preferences.firstOrNull { it.shouldUseViewHolder(viewHolder) } + return firstPreferences?.innerGroupPadding(viewHolder) ?: 0 + } + + override fun outerGroupPadding(viewHolder: ViewHolder): Int { + val firstPreferences = preferences.firstOrNull { it.shouldUseViewHolder(viewHolder) } + return firstPreferences?.outerGroupPadding(viewHolder) ?: 0 + } + + override fun isGroupItem(viewType: Int): Boolean { + return preferences.any { it.isGroupItem(viewType) } + } + + override fun shouldUseViewHolder(viewHolder: RecyclerView.ViewHolder): Boolean { + return preferences.any { it.shouldUseViewHolder(viewHolder) } + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index 2dc0a4819f..bb6c8fe7c7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -30,18 +30,10 @@ fun GroupedList.mapGroupedAssetsToUi( .filterIsInstance() } -private fun mapAssetsToAssetModels( - group: TokenGroupUi, - assets: List, - balance: (TotalAndTransferableBalance) -> Amount -): List { - return assets.map { TokenAssetUi(group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } -} - -private fun mapAssetGroupToUi( +fun mapAssetGroupToUi( assetGroup: TokenAssetGroup, assets: List, - groupBalance: (TokenAssetGroup) -> Amount + groupBalance: (TokenAssetGroup) -> Amount = { it.groupBalance.total } ): TokenGroupUi { val balance = groupBalance(assetGroup) return TokenGroupUi( @@ -51,7 +43,7 @@ private fun mapAssetGroupToUi( recentRateChange = assetGroup.token.coinRate?.recentRateChange.orZero().formatAsChange(), rateChangeColorRes = mapCoinRateChangeColorRes(assetGroup.token.coinRate), tokenSymbol = assetGroup.token.symbol.value, - groupWithOneItem = assetGroup.itemsCount == 1, + singleItemGroup = assetGroup.itemsCount <= 1, balance = AmountModel( token = balance.amount.formatTokenAmount(), fiat = balance.fiat.formatAsCurrency(assetGroup.token.currency) @@ -60,6 +52,14 @@ private fun mapAssetGroupToUi( ) } +fun mapAssetsToAssetModels( + group: TokenGroupUi, + assets: List, + balance: (TotalAndTransferableBalance) -> Amount +): List { + return assets.map { TokenAssetUi(group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } +} + private fun mapType( assetGroup: TokenAssetGroup, assets: List, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index af78541b2d..d7878b5eeb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -17,11 +17,11 @@ import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.BalanceBreakdownBottomSheet -import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetNetworkDecoration +import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.AssetBaseDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensItemAnimator import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter -import io.novafoundation.nova.feature_assets.presentation.balance.common.applyDefaultTo +import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.applyDefaultTo import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetsHeaderAdapter import io.novafoundation.nova.feature_assets.presentation.model.AssetModel @@ -77,7 +77,7 @@ class BalanceListFragment : balanceListAssets.addItemDecoration(AssetTokensDecoration(requireContext(), assetsAdapter, animator)) balanceListAssets.itemAnimator = AssetTokensItemAnimator(animationSettings, animator) - AssetNetworkDecoration.applyDefaultTo(balanceListAssets, assetsAdapter) + AssetBaseDecoration.applyDefaultTo(balanceListAssets, assetsAdapter) walletContainer.setOnRefreshListener { viewModel.fullSync() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt index 357bad4011..a3fddfd53f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt @@ -12,7 +12,7 @@ data class TokenGroupUi( val recentRateChange: String, @ColorRes val rateChangeColorRes: Int, val tokenSymbol: String, - val groupWithOneItem: Boolean, + val singleItemGroup: Boolean, val balance: AmountModel, val groupType: GroupType ) : AssetGroupRvItem, ExpandableParentItem { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt index cf0f7015d9..b85657e37a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt @@ -18,9 +18,9 @@ import io.novafoundation.nova.common.utils.submitListPreservingViewPoint import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent -import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetNetworkDecoration +import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.AssetBaseDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter -import io.novafoundation.nova.feature_assets.presentation.balance.common.applyDefaultTo +import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.applyDefaultTo import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import kotlinx.android.synthetic.main.fragment_asset_search.searchAssetContainer @@ -59,7 +59,7 @@ class AssetSearchFragment : searchAssetList.setHasFixedSize(true) searchAssetList.adapter = assetsAdapter - AssetNetworkDecoration.applyDefaultTo(searchAssetList, assetsAdapter) + AssetBaseDecoration.applyDefaultTo(searchAssetList, assetsAdapter) searchAssetList.itemAnimator = null searchAssetSearch.cancel.setOnClickListener { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowFragment.kt similarity index 84% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowFragment.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowFragment.kt index d71521ad63..400b8b0843 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowFragment.kt @@ -1,11 +1,11 @@ -package io.novafoundation.nova.feature_assets.presentation.buy.flow +package io.novafoundation.nova.feature_assets.presentation.buy.flow.asset import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi -import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowFragment import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixinUi import javax.inject.Inject @@ -26,10 +26,6 @@ class AssetBuyFlowFragment : AssetFlowFragment() { .inject(this) } - override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { - showMessage("Not implemented yet") - } - override fun subscribe(viewModel: AssetBuyFlowViewModel) { super.subscribe(viewModel) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt similarity index 74% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowViewModel.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt index 217d292c5e..0003f11513 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/AssetBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt @@ -1,14 +1,15 @@ -package io.novafoundation.nova.feature_assets.presentation.buy.flow +package io.novafoundation.nova.feature_assets.presentation.buy.flow.asset import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor -import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup -import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi +import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor @@ -35,7 +36,7 @@ class AssetBuyFlowViewModel( val buyMixin = buyMixinFactory.create(scope = this) - override fun searchAssetsFlow(): Flow>> { + override fun searchAssetsFlow(): Flow { return interactor.buyAssetSearch(query, externalBalancesFlow) } @@ -45,4 +46,8 @@ class AssetBuyFlowViewModel( buyMixin.buyClicked(chainAsset) } } + + override fun tokenClicked(assetModel: TokenGroupUi) { + router.openBuyNetworks(NetworkFlowPayload(assetModel.tokenSymbol)) + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/di/AssetBuyFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowComponent.kt similarity index 93% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/di/AssetBuyFlowComponent.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowComponent.kt index f6c85695eb..92a9d5749e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/di/AssetBuyFlowComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowComponent.kt @@ -1,10 +1,10 @@ -package io.novafoundation.nova.feature_assets.presentation.buy.flow.di +package io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.di import androidx.fragment.app.Fragment import dagger.BindsInstance import dagger.Subcomponent import io.novafoundation.nova.common.di.scope.ScreenScope -import io.novafoundation.nova.feature_assets.presentation.buy.flow.AssetBuyFlowFragment +import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowFragment @Subcomponent( modules = [ diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/di/AssetBuyFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt similarity index 98% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/di/AssetBuyFlowModule.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt index 8274e38108..d0c63c162e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/di/AssetBuyFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.buy.flow.di +package io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.di import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel @@ -14,7 +14,7 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.buy.flow.AssetBuyFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowViewModel import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt new file mode 100644 index 0000000000..8f381492e5 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt @@ -0,0 +1,30 @@ +package io.novafoundation.nova.feature_assets.presentation.buy.flow.network + +import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.feature_assets.R +import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi +import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi +import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment +import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixinUi +import javax.inject.Inject + +class NetworkBuyFlowFragment : NetworkFlowFragment() { + + @Inject + lateinit var buyMixin: BuyMixinUi + + override fun inject() { + FeatureUtils.getFeature(this, AssetsFeatureApi::class.java) + .networkBuyFlowComponent() + .create(this, payload) + .inject(this) + } + + override fun subscribe(viewModel: NetworkBuyFlowViewModel) { + super.subscribe(viewModel) + + buyMixin.setupBuyIntegration(this, viewModel.buyMixin) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt new file mode 100644 index 0000000000..d487af9481 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt @@ -0,0 +1,62 @@ +package io.novafoundation.nova.feature_assets.presentation.buy.flow.network + +import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.common.utils.TokenSymbol +import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase +import io.novafoundation.nova.feature_assets.R +import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor +import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.model.NetworkFlowRvItem +import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry +import io.novafoundation.nova.runtime.multiNetwork.asset +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.launch + +class NetworkBuyFlowViewModel( + interactor: AssetNetworksInteractor, + router: AssetsRouter, + externalBalancesInteractor: ExternalBalancesInteractor, + controllableAssetCheck: ControllableAssetCheckMixin, + accountUseCase: SelectedAccountUseCase, + buyMixinFactory: BuyMixin.Factory, + resourceManager: ResourceManager, + networkFlowPayload: NetworkFlowPayload, + private val chainRegistry: ChainRegistry +) : NetworkFlowViewModel( + interactor, + router, + controllableAssetCheck, + accountUseCase, + externalBalancesInteractor, + resourceManager, + networkFlowPayload +) { + + val buyMixin = buyMixinFactory.create(scope = this) + + override fun getAssetBalance(asset: AssetWithNetwork): Amount { + return asset.balanceWithOffChain.total + } + + override fun assetsFlow(tokenSymbol: TokenSymbol): Flow> { + return interactor.buyAssetFlow(tokenSymbol, externalBalancesFlow) + } + + override fun networkClicked(network: NetworkFlowRvItem) { + launch { + val chainAsset = chainRegistry.asset(network.chainId, network.assetId) + buyMixin.buyClicked(chainAsset) + } + } + + override fun getTitle(tokenSymbol: TokenSymbol): String { + return resourceManager.getString(R.string.buy_network_flow_title, tokenSymbol.value) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowComponent.kt new file mode 100644 index 0000000000..754b9a018a --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowComponent.kt @@ -0,0 +1,29 @@ +package io.novafoundation.nova.feature_assets.presentation.buy.flow.network.di + +import androidx.fragment.app.Fragment +import dagger.BindsInstance +import dagger.Subcomponent +import io.novafoundation.nova.common.di.scope.ScreenScope +import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowFragment +import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload + +@Subcomponent( + modules = [ + NetworkBuyFlowModule::class + ] +) +@ScreenScope +interface NetworkBuyFlowComponent { + + @Subcomponent.Factory + interface Factory { + + fun create( + @BindsInstance fragment: Fragment, + @BindsInstance networkFlowPayload: NetworkFlowPayload + ): NetworkBuyFlowComponent + } + + fun inject(fragment: NetworkBuyFlowFragment) +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowModule.kt new file mode 100644 index 0000000000..fec4736786 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowModule.kt @@ -0,0 +1,56 @@ +package io.novafoundation.nova.feature_assets.presentation.buy.flow.network.di + +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import dagger.Module +import dagger.Provides +import dagger.multibindings.IntoMap +import io.novafoundation.nova.common.di.viewmodel.ViewModelKey +import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase +import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor +import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry + +@Module(includes = [ViewModelModule::class]) +class NetworkBuyFlowModule { + + @Provides + internal fun provideViewModel(fragment: Fragment, factory: ViewModelProvider.Factory): NetworkBuyFlowViewModel { + return ViewModelProvider(fragment, factory).get(NetworkBuyFlowViewModel::class.java) + } + + @Provides + @IntoMap + @ViewModelKey(NetworkBuyFlowViewModel::class) + fun provideViewModel( + interactor: AssetNetworksInteractor, + router: AssetsRouter, + externalBalancesInteractor: ExternalBalancesInteractor, + controllableAssetCheck: ControllableAssetCheckMixin, + accountUseCase: SelectedAccountUseCase, + buyMixinFactory: BuyMixin.Factory, + resourceManager: ResourceManager, + networkFlowPayload: NetworkFlowPayload, + chainRegistry: ChainRegistry + ): ViewModel { + return NetworkBuyFlowViewModel( + interactor = interactor, + router = router, + externalBalancesInteractor = externalBalancesInteractor, + controllableAssetCheck = controllableAssetCheck, + accountUseCase = accountUseCase, + buyMixinFactory = buyMixinFactory, + resourceManager = resourceManager, + networkFlowPayload = networkFlowPayload, + chainRegistry = chainRegistry + ) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt similarity index 72% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowFragment.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt index b9e6d4a0ae..42c80a8c9f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.flow +package io.novafoundation.nova.feature_assets.presentation.flow.asset import android.os.Bundle import android.view.LayoutInflater @@ -17,9 +17,13 @@ import io.novafoundation.nova.common.utils.keyboard.showSoftKeyboard import io.novafoundation.nova.common.utils.submitListPreservingViewPoint import io.novafoundation.nova.common.view.setModelOrHide import io.novafoundation.nova.feature_assets.R -import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetNetworkDecoration +import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.AssetBaseDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter -import io.novafoundation.nova.feature_assets.presentation.balance.common.applyDefaultTo +import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.CompoundAssetDecorationPreferences +import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.NetworkAssetDecorationPreferences +import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.TokenAssetGroupDecorationPreferences +import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.applyDefaultTo +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.receive.view.LedgerNotSupportedWarningBottomSheet import javax.inject.Inject @@ -64,7 +68,14 @@ abstract class AssetFlowFragment : setHasFixedSize(true) adapter = assetsAdapter - AssetNetworkDecoration.applyDefaultTo(this, assetsAdapter) + AssetBaseDecoration.applyDefaultTo( + this, + assetsAdapter, + CompoundAssetDecorationPreferences( + NetworkAssetDecorationPreferences(), + TokenAssetGroupDecorationPreferences() + ) + ) itemAnimator = null } @@ -75,17 +86,20 @@ abstract class AssetFlowFragment : override fun subscribe(viewModel: T) { assetFlowToolbar.searchField.content.bindTo(viewModel.query, lifecycleScope) - viewModel.searchResults.observe { searchResult -> - assetFlowPlaceholder.setModelOrHide(searchResult.placeholder) - assetFlowList.setVisible(searchResult.assets.isNotEmpty()) + viewModel.searchResults.observe { assets -> + assetFlowList.setVisible(assets.isNotEmpty()) assetsAdapter.submitListPreservingViewPoint( - data = searchResult.assets, + data = assets, into = assetFlowList, extraDiffCompletedCallback = { assetFlowList.invalidateItemDecorations() } ) } + viewModel.placeholder.observe { placeholder -> + assetFlowPlaceholder.setModelOrHide(placeholder) + } + viewModel.acknowledgeLedgerWarning.awaitableActionLiveData.observeEvent { LedgerNotSupportedWarningBottomSheet( context = requireContext(), @@ -100,4 +114,10 @@ abstract class AssetFlowFragment : assetFlowToolbar.searchField.hideSoftKeyboard() } + + override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { + viewModel.tokenClicked(tokenGroup) + + assetFlowToolbar.searchField.hideSoftKeyboard() + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt similarity index 68% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowViewModel.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index a65e5a957a..5fc4efb4a5 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.flow +package io.novafoundation.nova.feature_assets.presentation.flow.asset import io.novafoundation.nova.common.base.BaseViewModel import io.novafoundation.nova.common.resources.ResourceManager @@ -8,13 +8,18 @@ import io.novafoundation.nova.common.view.PlaceholderModel import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.assets.models.toList import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapAssetGroupToUi import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency @@ -23,13 +28,9 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch -class AssetFlowListModel( - val assets: List, - val placeholder: PlaceholderModel?, -) - abstract class AssetFlowViewModel( protected val interactor: AssetSearchInteractor, protected val router: AssetsRouter, @@ -50,31 +51,43 @@ abstract class AssetFlowViewModel( protected val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() + private val searchAssetsFlow = flowOfAll { searchAssetsFlow() } + val searchResults = combine( - flowOfAll { searchAssetsFlow() }, // lazy use searchAssetsFlow to let subclasses initialize self + searchAssetsFlow, // lazy use searchAssetsFlow to let subclasses initialize self selectedCurrency, ) { assets, currency -> - val groupedAssets = mapAssets(assets, currency) - AssetFlowListModel( - groupedAssets, - getPlaceholder(query.value, groupedAssets) - ) - } - .distinctUntilChanged() + mapAssets(assets, currency) + }.distinctUntilChanged() .shareInBackground(SharingStarted.Lazily) + val placeholder = searchAssetsFlow.map { getPlaceholder(query.value, it.toList()) } + fun backClicked() { router.back() } - abstract fun searchAssetsFlow(): Flow>> + abstract fun searchAssetsFlow(): Flow abstract fun assetClicked(assetModel: AssetModel) - open fun mapAssets(assets: Map>, currency: Currency): List { + abstract fun tokenClicked(assetModel: TokenGroupUi) + + private fun mapAssets(searchResult: AssetFlowSearchResult, currency: Currency): List { + return when (searchResult) { + is AssetFlowSearchResult.ByNetworks -> mapNetworkAssets(searchResult.assets, currency) + is AssetFlowSearchResult.ByTokens -> mapTokensAssets(searchResult.tokens) + } + } + + open fun mapNetworkAssets(assets: Map>, currency: Currency): List { return assets.mapGroupedAssetsToUi(currency) } + open fun mapTokensAssets(assets: List): List { + return assets.map { mapAssetGroupToUi(it, assets = emptyList()) } + } + internal fun validate(assetModel: AssetModel, onAccept: (AssetModel) -> Unit) { launch { val metaAccount = accountUseCase.getSelectedMetaAccount() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowAdapter.kt new file mode 100644 index 0000000000..17dd942009 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowAdapter.kt @@ -0,0 +1,61 @@ +package io.novafoundation.nova.feature_assets.presentation.flow.network + +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import coil.ImageLoader +import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.common.utils.inflateChild +import io.novafoundation.nova.feature_account_api.presenatation.chain.loadChainIcon +import io.novafoundation.nova.feature_assets.R +import io.novafoundation.nova.feature_assets.presentation.flow.network.model.NetworkFlowRvItem +import kotlinx.android.synthetic.main.item_network_flow.view.itemNetworkBalance +import kotlinx.android.synthetic.main.item_network_flow.view.itemNetworkImage +import kotlinx.android.synthetic.main.item_network_flow.view.itemNetworkPriceAmount +import kotlinx.android.synthetic.main.item_network_flow.view.itemNetworkName + +class NetworkFlowAdapter( + private val imageLoader: ImageLoader, + private val itemHandler: ItemNetworkHandler, +) : ListAdapter(DiffCallback) { + + interface ItemNetworkHandler { + fun networkClicked(network: NetworkFlowRvItem) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NetworkFlowViewHolder { + return NetworkFlowViewHolder(parent.inflateChild(R.layout.item_network_flow), imageLoader, itemHandler) + } + + override fun onBindViewHolder(holder: NetworkFlowViewHolder, position: Int) { + holder.bind(getItem(position)) + } +} + +private object DiffCallback : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: NetworkFlowRvItem, newItem: NetworkFlowRvItem): Boolean { + return oldItem.chainId == newItem.chainId + } + + override fun areContentsTheSame(oldItem: NetworkFlowRvItem, newItem: NetworkFlowRvItem): Boolean { + return oldItem == newItem + } +} + +class NetworkFlowViewHolder( + containerView: View, + private val imageLoader: ImageLoader, + private val itemHandler: NetworkFlowAdapter.ItemNetworkHandler, +) : GroupedListHolder(containerView) { + + fun bind(item: NetworkFlowRvItem) = with(containerView) { + itemNetworkImage.loadChainIcon(item.icon, imageLoader) + itemNetworkName.text = item.networkName + itemNetworkBalance.text = item.balance.token + itemNetworkPriceAmount.text = item.balance.fiat + + setOnClickListener { itemHandler.networkClicked(item) } + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt new file mode 100644 index 0000000000..dbd8e7d9cd --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt @@ -0,0 +1,88 @@ +package io.novafoundation.nova.feature_assets.presentation.flow.network + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.StringRes +import androidx.recyclerview.widget.ConcatAdapter +import coil.ImageLoader +import io.novafoundation.nova.common.base.BaseFragment +import io.novafoundation.nova.common.utils.FragmentPayloadCreator +import io.novafoundation.nova.common.utils.FragmentPayloadHolder +import io.novafoundation.nova.common.utils.PayloadCreator +import io.novafoundation.nova.common.utils.applyStatusBarInsets +import io.novafoundation.nova.common.view.recyclerview.adapter.text.TextAdapter +import io.novafoundation.nova.feature_assets.R +import io.novafoundation.nova.feature_assets.presentation.flow.network.model.NetworkFlowRvItem +import io.novafoundation.nova.feature_assets.presentation.receive.view.LedgerNotSupportedWarningBottomSheet +import javax.inject.Inject +import kotlinx.android.synthetic.main.fragment_asset_flow_search.assetFlowToolbar +import kotlinx.android.synthetic.main.fragment_network_flow.networkFlowList +import kotlinx.android.synthetic.main.fragment_network_flow.networkFlowToolbar + +abstract class NetworkFlowFragment : + BaseFragment(), + FragmentPayloadHolder, + NetworkFlowAdapter.ItemNetworkHandler { + + companion object : PayloadCreator by FragmentPayloadCreator() + + @Inject + lateinit var imageLoader: ImageLoader + + private val titleAdapter by lazy(LazyThreadSafetyMode.NONE) { + TextAdapter(styleRes = R.style.TextAppearance_NovaFoundation_Bold_Title3) + } + + private val networkAdapter by lazy(LazyThreadSafetyMode.NONE) { + NetworkFlowAdapter(imageLoader, this) + } + + private val adapter by lazy(LazyThreadSafetyMode.NONE) { + ConcatAdapter(titleAdapter, networkAdapter) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return layoutInflater.inflate(R.layout.fragment_network_flow, container, false) + } + + fun setTitle(@StringRes titleRes: Int) { + assetFlowToolbar.setTitle(titleRes) + } + + override fun initViews() { + networkFlowToolbar.applyStatusBarInsets() + networkFlowToolbar.setHomeButtonListener { viewModel.backClicked() } + + networkFlowList.setHasFixedSize(true) + networkFlowList.adapter = adapter + networkFlowList.itemAnimator = null + } + + override fun subscribe(viewModel: T) { + viewModel.titleFlow.observe { + titleAdapter.setText(it) + } + + viewModel.networks.observe { + networkAdapter.submitList(it) + } + + viewModel.acknowledgeLedgerWarning.awaitableActionLiveData.observeEvent { + LedgerNotSupportedWarningBottomSheet( + context = requireContext(), + onSuccess = { it.onSuccess(Unit) }, + message = it.payload + ).show() + } + } + + override fun networkClicked(network: NetworkFlowRvItem) { + viewModel.networkClicked(network) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowPayload.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowPayload.kt new file mode 100644 index 0000000000..4af40784f4 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowPayload.kt @@ -0,0 +1,10 @@ +package io.novafoundation.nova.feature_assets.presentation.flow.network + +import android.os.Parcelable +import io.novafoundation.nova.common.utils.TokenSymbol +import kotlinx.android.parcel.Parcelize + +@Parcelize +class NetworkFlowPayload(val tokenSymbol: String) : Parcelable + +fun NetworkFlowPayload.asTokenSymbol() = TokenSymbol(tokenSymbol) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt new file mode 100644 index 0000000000..1f1fb0eec8 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt @@ -0,0 +1,77 @@ +package io.novafoundation.nova.feature_assets.presentation.flow.network + +import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.common.utils.TokenSymbol +import io.novafoundation.nova.common.utils.flowOf +import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase +import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor +import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.flow.network.model.NetworkFlowRvItem +import io.novafoundation.nova.feature_assets.presentation.model.AssetModel +import io.novafoundation.nova.feature_wallet_api.presentation.model.mapAmountToAmountModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch + +abstract class NetworkFlowViewModel( + protected val interactor: AssetNetworksInteractor, + protected val router: AssetsRouter, + private val controllableAssetCheck: ControllableAssetCheckMixin, + internal val accountUseCase: SelectedAccountUseCase, + externalBalancesInteractor: ExternalBalancesInteractor, + internal val resourceManager: ResourceManager, + private val networkFlowPayload: NetworkFlowPayload +) : BaseViewModel() { + + val acknowledgeLedgerWarning = controllableAssetCheck.acknowledgeLedgerWarning + + protected val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() + + val titleFlow: Flow = flowOf { getTitle(networkFlowPayload.asTokenSymbol()) } + val networks: Flow> = assetsFlow(networkFlowPayload.asTokenSymbol()) + .map { mapAssets(it) } + + abstract fun getAssetBalance(asset: AssetWithNetwork): Amount + + abstract fun assetsFlow(tokenSymbol: TokenSymbol): Flow> + + abstract fun networkClicked(network: NetworkFlowRvItem) + + abstract fun getTitle(tokenSymbol: TokenSymbol): String + + fun backClicked() { + router.back() + } + + internal fun validate(assetModel: AssetModel, onAccept: (AssetModel) -> Unit) { + launch { + val metaAccount = accountUseCase.getSelectedMetaAccount() + val chainAsset = assetModel.token.configuration + controllableAssetCheck.check(metaAccount, chainAsset) { + onAccept(assetModel) + } + } + } + + private fun mapAssets(assetWithNetworks: List): List { + return assetWithNetworks + .map { + NetworkFlowRvItem( + it.chain.id, + it.asset.token.configuration.id, + it.chain.name, + it.chain.icon, + mapAmountToAmountModel( + amount = getAssetBalance(it).amount, + asset = it.asset, + includeAssetTicker = false + ) + ) + } + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/model/NetworkFlowRvItem.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/model/NetworkFlowRvItem.kt new file mode 100644 index 0000000000..051b6cd2fc --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/model/NetworkFlowRvItem.kt @@ -0,0 +1,11 @@ +package io.novafoundation.nova.feature_assets.presentation.flow.network.model + +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel + +data class NetworkFlowRvItem( + val chainId: String, + val assetId: Int, + val networkName: String, + val icon: String?, + val balance: AmountModel +) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowFragment.kt index f5edf8aede..1956f3d139 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowFragment.kt @@ -5,7 +5,7 @@ import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi -import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowFragment class AssetReceiveFlowFragment : AssetFlowFragment() { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowViewModel.kt index 7069f5499f..a33ac519d6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowViewModel.kt @@ -3,13 +3,13 @@ package io.novafoundation.nova.feature_assets.presentation.receive.flow import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor -import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup -import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi +import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowViewModel import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import kotlinx.coroutines.flow.Flow @@ -31,8 +31,8 @@ class AssetReceiveFlowViewModel( externalBalancesInteractor, resourceManager, ) { - override fun searchAssetsFlow(): Flow>> { - return interactor.searchAssetsFlow(query, externalBalancesFlow) + override fun searchAssetsFlow(): Flow { + return interactor.searchReceiveAssetsFlow(query, externalBalancesFlow) } override fun assetClicked(assetModel: AssetModel) { @@ -41,6 +41,9 @@ class AssetReceiveFlowViewModel( } } + override fun tokenClicked(assetModel: TokenGroupUi) { + } + private fun openNextScreen(assetModel: AssetModel) { val chainAsset = assetModel.token.configuration val assePayload = AssetPayload(chainAsset.chainId, chainAsset.id) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowFragment.kt index b28ac4f91f..84ffd426f3 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowFragment.kt @@ -5,7 +5,7 @@ import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi -import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowFragment import kotlinx.android.synthetic.main.fragment_asset_flow_search.assetFlowPlaceholder class AssetSendFlowFragment : AssetFlowFragment() { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt index 1576b47bb6..1d843b94b7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt @@ -5,15 +5,19 @@ import io.novafoundation.nova.common.view.PlaceholderModel import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.domain.common.TotalAndTransferableBalance import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapAssetGroupToUi import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem -import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi +import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowViewModel import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor @@ -39,7 +43,7 @@ class AssetSendFlowViewModel( resourceManager, ) { - override fun searchAssetsFlow(): Flow>> { + override fun searchAssetsFlow(): Flow { return interactor.sendAssetSearch(query, externalBalancesFlow) } @@ -49,10 +53,19 @@ class AssetSendFlowViewModel( router.openSend(SendPayload.SpecifiedOrigin(assetPayload)) } - override fun mapAssets(assets: Map>, currency: Currency): List { + override fun tokenClicked(assetModel: TokenGroupUi) { + } + + override fun mapNetworkAssets(assets: Map>, currency: Currency): List { return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, TotalAndTransferableBalance::transferable) } + override fun mapTokensAssets(assets: List): List { + return assets.map { + mapAssetGroupToUi(it, assets = emptyList()) { it.groupBalance.transferable } + } + } + override fun getPlaceholder(query: String, assets: List): PlaceholderModel? { if (query.isEmpty() && assets.isEmpty()) { return PlaceholderModel( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowFragment.kt index f852418309..c7b8140cfc 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowFragment.kt @@ -5,7 +5,7 @@ import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi -import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowFragment class AssetSwapFlowFragment : AssetFlowFragment() { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt index ad84bc9623..fece67d048 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt @@ -6,15 +6,19 @@ import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.domain.common.TotalAndTransferableBalance import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapAssetGroupToUi import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem -import io.novafoundation.nova.feature_assets.presentation.flow.AssetFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi +import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowViewModel import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.swap.executor.SwapFlowExecutor import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor @@ -59,7 +63,7 @@ class AssetSwapFlowViewModel( } } - override fun searchAssetsFlow(): Flow>> { + override fun searchAssetsFlow(): Flow { return interactor.searchSwapAssetsFlow( forAsset = payload.constraintDirectionsAsset?.fullChainAssetId, queryFlow = query, @@ -75,7 +79,16 @@ class AssetSwapFlowViewModel( } } - override fun mapAssets(assets: Map>, currency: Currency): List { + override fun tokenClicked(assetModel: TokenGroupUi) { + } + + override fun mapNetworkAssets(assets: Map>, currency: Currency): List { return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, TotalAndTransferableBalance::transferable) } + + override fun mapTokensAssets(assets: List): List { + return assets.map { + mapAssetGroupToUi(it, assets = emptyList()) { it.groupBalance.transferable } + } + } } diff --git a/feature-assets/src/main/res/layout/fragment_network_flow.xml b/feature-assets/src/main/res/layout/fragment_network_flow.xml new file mode 100644 index 0000000000..854f50df70 --- /dev/null +++ b/feature-assets/src/main/res/layout/fragment_network_flow.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/feature-assets/src/main/res/layout/item_network_flow.xml b/feature-assets/src/main/res/layout/item_network_flow.xml new file mode 100644 index 0000000000..50464461dd --- /dev/null +++ b/feature-assets/src/main/res/layout/item_network_flow.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + From 63bbb5b2016ebd10600733d020f0b201c2d99b03 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 24 Oct 2024 13:31:37 +0200 Subject: [PATCH 19/78] Send/Receive network flows --- .../nova/app/root/navigation/Navigator.kt | 8 +-- .../app/root/navigation/swap/SwapNavigator.kt | 4 +- .../main/res/navigation/main_nav_graph.xml | 35 +++++++++-- .../res/navigation/start_swap_nav_graph.xml | 2 +- common/src/main/res/values/strings.xml | 2 + .../di/AssetsFeatureComponent.kt | 13 +++- .../networks/AssetNetworksInteractor.kt | 2 +- .../flow/network/NetworkBuyFlowViewModel.kt | 5 +- .../flow/network/NetworkFlowFragment.kt | 4 -- .../flow/network/NetworkFlowViewModel.kt | 11 ++-- .../{ => asset}/AssetReceiveFlowFragment.kt | 7 +-- .../{ => asset}/AssetReceiveFlowViewModel.kt | 4 +- .../di/AssetReceiveFlowComponent.kt | 4 +- .../{ => asset}/di/AssetReceiveFlowModule.kt | 4 +- .../network/NetworkReceiveFlowFragment.kt | 16 +++++ .../network/NetworkReceiveFlowViewModel.kt | 57 ++++++++++++++++++ .../network/di/NetworkReceiveFlowComponent.kt | 30 ++++++++++ .../network/di/NetworkReceiveFlowModule.kt | 55 +++++++++++++++++ .../flow/{ => asset}/AssetSendFlowFragment.kt | 6 +- .../{ => asset}/AssetSendFlowViewModel.kt | 4 +- .../{ => asset}/di/AssetSendFlowComponent.kt | 4 +- .../{ => asset}/di/AssetSendFlowModule.kt | 4 +- .../flow/network/NetworkSendFlowFragment.kt | 16 +++++ .../flow/network/NetworkSendFlowViewModel.kt | 59 +++++++++++++++++++ .../network/di/NetworkSendFlowComponent.kt | 30 ++++++++++ .../flow/network/di/NetworkSendFlowModule.kt | 55 +++++++++++++++++ .../swap/{ => asset}/AssetSwapFlowFragment.kt | 2 +- .../{ => asset}/AssetSwapFlowViewModel.kt | 2 +- .../swap/{ => asset}/SwapFlowPayload.kt | 2 +- .../swap/di/AssetSwapFlowComponent.kt | 4 +- .../swap/di/AssetSwapFlowModule.kt | 4 +- .../swap/executor/SwapFlowExecutor.kt | 2 +- .../swap/network/NetworkSwapFlowFragment.kt | 16 +++++ .../swap/network/NetworkSwapFlowViewModel.kt | 59 +++++++++++++++++++ .../network/di/NetworkSwapFlowComponent.kt | 31 ++++++++++ .../swap/network/di/NetworkSwapFlowModule.kt | 56 ++++++++++++++++++ 36 files changed, 566 insertions(+), 53 deletions(-) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/{ => asset}/AssetReceiveFlowFragment.kt (78%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/{ => asset}/AssetReceiveFlowViewModel.kt (92%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/{ => asset}/di/AssetReceiveFlowComponent.kt (91%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/{ => asset}/di/AssetReceiveFlowModule.kt (97%) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowComponent.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowModule.kt rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/{ => asset}/AssetSendFlowFragment.kt (90%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/{ => asset}/AssetSendFlowViewModel.kt (95%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/{ => asset}/di/AssetSendFlowComponent.kt (93%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/{ => asset}/di/AssetSendFlowModule.kt (97%) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowComponent.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowModule.kt rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/{ => asset}/AssetSwapFlowFragment.kt (94%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/{ => asset}/AssetSwapFlowViewModel.kt (98%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/{ => asset}/SwapFlowPayload.kt (91%) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowComponent.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowModule.kt diff --git a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt index b8cd08b0b6..4fd0208578 100644 --- a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt +++ b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt @@ -60,8 +60,8 @@ import io.novafoundation.nova.feature_assets.presentation.send.TransferDraft import io.novafoundation.nova.feature_assets.presentation.send.amount.SelectSendFragment import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload import io.novafoundation.nova.feature_assets.presentation.send.confirm.ConfirmSendFragment -import io.novafoundation.nova.feature_assets.presentation.swap.AssetSwapFlowFragment -import io.novafoundation.nova.feature_assets.presentation.swap.SwapFlowPayload +import io.novafoundation.nova.feature_assets.presentation.swap.asset.AssetSwapFlowFragment +import io.novafoundation.nova.feature_assets.presentation.swap.asset.SwapFlowPayload import io.novafoundation.nova.feature_assets.presentation.tokens.add.enterInfo.AddTokenEnterInfoFragment import io.novafoundation.nova.feature_assets.presentation.tokens.add.enterInfo.AddTokenEnterInfoPayload import io.novafoundation.nova.feature_assets.presentation.tokens.manage.chain.ManageChainTokensFragment @@ -386,11 +386,11 @@ class Navigator( } override fun openSendNetworks(networkFlowPayload: NetworkFlowPayload) { - TODO("Not yet implemented") + navController?.navigate(R.id.action_sendFlow_to_sendFlowNetwork, NetworkFlowFragment.createPayload(networkFlowPayload)) } override fun openReceiveNetworks(networkFlowPayload: NetworkFlowPayload) { - TODO("Not yet implemented") + navController?.navigate(R.id.action_receiveFlow_to_receiveFlowNetwork, NetworkFlowFragment.createPayload(networkFlowPayload)) } override fun openSwapNetworks(networkFlowPayload: NetworkFlowPayload) { diff --git a/app/src/main/java/io/novafoundation/nova/app/root/navigation/swap/SwapNavigator.kt b/app/src/main/java/io/novafoundation/nova/app/root/navigation/swap/SwapNavigator.kt index 99cbbb0e24..a52457f9d9 100644 --- a/app/src/main/java/io/novafoundation/nova/app/root/navigation/swap/SwapNavigator.kt +++ b/app/src/main/java/io/novafoundation/nova/app/root/navigation/swap/SwapNavigator.kt @@ -6,8 +6,8 @@ import io.novafoundation.nova.app.root.navigation.NavigationHolder import io.novafoundation.nova.app.root.navigation.Navigator import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload import io.novafoundation.nova.feature_assets.presentation.balance.detail.BalanceDetailFragment -import io.novafoundation.nova.feature_assets.presentation.swap.AssetSwapFlowFragment -import io.novafoundation.nova.feature_assets.presentation.swap.SwapFlowPayload +import io.novafoundation.nova.feature_assets.presentation.swap.asset.AssetSwapFlowFragment +import io.novafoundation.nova.feature_assets.presentation.swap.asset.SwapFlowPayload import io.novafoundation.nova.feature_swap_impl.presentation.SwapRouter import io.novafoundation.nova.feature_swap_impl.presentation.confirmation.SwapConfirmationFragment import io.novafoundation.nova.feature_swap_impl.presentation.confirmation.payload.SwapConfirmationPayload diff --git a/app/src/main/res/navigation/main_nav_graph.xml b/app/src/main/res/navigation/main_nav_graph.xml index 5d3114f58e..fec0a2f29f 100644 --- a/app/src/main/res/navigation/main_nav_graph.xml +++ b/app/src/main/res/navigation/main_nav_graph.xml @@ -872,7 +872,7 @@ + + android:name="io.novafoundation.nova.feature_assets.presentation.receive.flow.asset.AssetReceiveFlowFragment" + android:label="AssetReceiveFlowFragment"> + + + + + + + + Select network for buying %s + Select network for receiving %s + Select network for sending %s Tokens Networks diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt index e886670fa8..693d51ccbc 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt @@ -15,11 +15,14 @@ import io.novafoundation.nova.feature_assets.presentation.balance.search.di.Asse import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.di.AssetBuyFlowComponent import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.di.NetworkBuyFlowComponent import io.novafoundation.nova.feature_assets.presentation.receive.di.ReceiveComponent -import io.novafoundation.nova.feature_assets.presentation.receive.flow.di.AssetReceiveFlowComponent +import io.novafoundation.nova.feature_assets.presentation.receive.flow.asset.di.AssetReceiveFlowComponent +import io.novafoundation.nova.feature_assets.presentation.receive.flow.network.di.NetworkReceiveFlowComponent import io.novafoundation.nova.feature_assets.presentation.send.amount.di.SelectSendComponent import io.novafoundation.nova.feature_assets.presentation.send.confirm.di.ConfirmSendComponent -import io.novafoundation.nova.feature_assets.presentation.send.flow.di.AssetSendFlowComponent +import io.novafoundation.nova.feature_assets.presentation.send.flow.asset.di.AssetSendFlowComponent +import io.novafoundation.nova.feature_assets.presentation.send.flow.network.di.NetworkSendFlowComponent import io.novafoundation.nova.feature_assets.presentation.swap.di.AssetSwapFlowComponent +import io.novafoundation.nova.feature_assets.presentation.swap.network.di.NetworkSwapFlowComponent import io.novafoundation.nova.feature_assets.presentation.tokens.add.enterInfo.di.AddTokenEnterInfoComponent import io.novafoundation.nova.feature_assets.presentation.tokens.add.selectChain.di.AddTokenSelectChainComponent import io.novafoundation.nova.feature_assets.presentation.tokens.manage.chain.di.ManageChainTokensComponent @@ -94,6 +97,12 @@ interface AssetsFeatureComponent : AssetsFeatureApi { fun networkBuyFlowComponent(): NetworkBuyFlowComponent.Factory + fun networkReceiveFlowComponent(): NetworkReceiveFlowComponent.Factory + + fun networkSendFlowComponent(): NetworkSendFlowComponent.Factory + + fun networkSwapFlowComponent(): NetworkSwapFlowComponent.Factory + fun inject(view: GoToNftsView) @Component.Factory diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt index 2d0181d010..a812e26a2b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt @@ -79,7 +79,7 @@ class AssetNetworksInteractor( return searchAssetsByTokenSymbolInternalFlow(tokenSymbol, externalBalancesFlow, filterFlow = filterFlow) } - fun receiveAssetsFlow( + fun receiveAssetFlow( tokenSymbol: TokenSymbol, externalBalancesFlow: Flow>, ): Flow> { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt index d487af9481..92b8063933 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt @@ -28,7 +28,7 @@ class NetworkBuyFlowViewModel( buyMixinFactory: BuyMixin.Factory, resourceManager: ResourceManager, networkFlowPayload: NetworkFlowPayload, - private val chainRegistry: ChainRegistry + chainRegistry: ChainRegistry ) : NetworkFlowViewModel( interactor, router, @@ -36,7 +36,8 @@ class NetworkBuyFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, - networkFlowPayload + networkFlowPayload, + chainRegistry ) { val buyMixin = buyMixinFactory.create(scope = this) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt index dbd8e7d9cd..d774f6ba9f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt @@ -51,10 +51,6 @@ abstract class NetworkFlowFragment : return layoutInflater.inflate(R.layout.fragment_network_flow, container, false) } - fun setTitle(@StringRes titleRes: Int) { - assetFlowToolbar.setTitle(titleRes) - } - override fun initViews() { networkFlowToolbar.applyStatusBarInsets() networkFlowToolbar.setHomeButtonListener { viewModel.backClicked() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt index 1f1fb0eec8..9397da2687 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt @@ -14,6 +14,8 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.Control import io.novafoundation.nova.feature_assets.presentation.flow.network.model.NetworkFlowRvItem import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_wallet_api.presentation.model.mapAmountToAmountModel +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry +import io.novafoundation.nova.runtime.multiNetwork.asset import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @@ -25,7 +27,8 @@ abstract class NetworkFlowViewModel( internal val accountUseCase: SelectedAccountUseCase, externalBalancesInteractor: ExternalBalancesInteractor, internal val resourceManager: ResourceManager, - private val networkFlowPayload: NetworkFlowPayload + private val networkFlowPayload: NetworkFlowPayload, + internal val chainRegistry: ChainRegistry ) : BaseViewModel() { val acknowledgeLedgerWarning = controllableAssetCheck.acknowledgeLedgerWarning @@ -48,12 +51,12 @@ abstract class NetworkFlowViewModel( router.back() } - internal fun validate(assetModel: AssetModel, onAccept: (AssetModel) -> Unit) { + internal fun validate(networkFlowRvItem: NetworkFlowRvItem, onAccept: () -> Unit) { launch { val metaAccount = accountUseCase.getSelectedMetaAccount() - val chainAsset = assetModel.token.configuration + val chainAsset = chainRegistry.asset(networkFlowRvItem.chainId, networkFlowRvItem.assetId) controllableAssetCheck.check(metaAccount, chainAsset) { - onAccept(assetModel) + onAccept() } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowFragment.kt similarity index 78% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowFragment.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowFragment.kt index 1956f3d139..2efa084697 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowFragment.kt @@ -1,10 +1,9 @@ -package io.novafoundation.nova.feature_assets.presentation.receive.flow +package io.novafoundation.nova.feature_assets.presentation.receive.flow.asset import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent -import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowFragment class AssetReceiveFlowFragment : AssetFlowFragment() { @@ -20,8 +19,4 @@ class AssetReceiveFlowFragment : AssetFlowFragment() .create(this) .inject(this) } - - override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { - showMessage("Not implemented yet") - } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt similarity index 92% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowViewModel.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt index a33ac519d6..e5a621b90f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/AssetReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.receive.flow +package io.novafoundation.nova.feature_assets.presentation.receive.flow.asset import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -10,6 +10,7 @@ import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import kotlinx.coroutines.flow.Flow @@ -42,6 +43,7 @@ class AssetReceiveFlowViewModel( } override fun tokenClicked(assetModel: TokenGroupUi) { + router.openReceiveNetworks(NetworkFlowPayload(assetModel.tokenSymbol)) } private fun openNextScreen(assetModel: AssetModel) { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/di/AssetReceiveFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowComponent.kt similarity index 91% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/di/AssetReceiveFlowComponent.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowComponent.kt index 5bc9f0c190..788b624e45 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/di/AssetReceiveFlowComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowComponent.kt @@ -1,10 +1,10 @@ -package io.novafoundation.nova.feature_assets.presentation.receive.flow.di +package io.novafoundation.nova.feature_assets.presentation.receive.flow.asset.di import androidx.fragment.app.Fragment import dagger.BindsInstance import dagger.Subcomponent import io.novafoundation.nova.common.di.scope.ScreenScope -import io.novafoundation.nova.feature_assets.presentation.receive.flow.AssetReceiveFlowFragment +import io.novafoundation.nova.feature_assets.presentation.receive.flow.asset.AssetReceiveFlowFragment @Subcomponent( modules = [ diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/di/AssetReceiveFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt similarity index 97% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/di/AssetReceiveFlowModule.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt index f85f02ef93..b918a582c8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/di/AssetReceiveFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.receive.flow.di +package io.novafoundation.nova.feature_assets.presentation.receive.flow.asset.di import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel @@ -14,7 +14,7 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.receive.flow.AssetReceiveFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.receive.flow.asset.AssetReceiveFlowViewModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor @Module(includes = [ViewModelModule::class]) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt new file mode 100644 index 0000000000..5d23c1e35a --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt @@ -0,0 +1,16 @@ +package io.novafoundation.nova.feature_assets.presentation.receive.flow.network + +import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi +import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment + +class NetworkReceiveFlowFragment : NetworkFlowFragment() { + + override fun inject() { + FeatureUtils.getFeature(this, AssetsFeatureApi::class.java) + .networkReceiveFlowComponent() + .create(this, payload) + .inject(this) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt new file mode 100644 index 0000000000..bcf942eb1d --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt @@ -0,0 +1,57 @@ +package io.novafoundation.nova.feature_assets.presentation.receive.flow.network + +import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.common.utils.TokenSymbol +import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase +import io.novafoundation.nova.feature_assets.R +import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor +import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.model.NetworkFlowRvItem +import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry +import kotlinx.coroutines.flow.Flow + +class NetworkReceiveFlowViewModel( + interactor: AssetNetworksInteractor, + router: AssetsRouter, + externalBalancesInteractor: ExternalBalancesInteractor, + controllableAssetCheck: ControllableAssetCheckMixin, + accountUseCase: SelectedAccountUseCase, + resourceManager: ResourceManager, + networkFlowPayload: NetworkFlowPayload, + chainRegistry: ChainRegistry +) : NetworkFlowViewModel( + interactor, + router, + controllableAssetCheck, + accountUseCase, + externalBalancesInteractor, + resourceManager, + networkFlowPayload, + chainRegistry +) { + + override fun getAssetBalance(asset: AssetWithNetwork): Amount { + return asset.balanceWithOffChain.total + } + + override fun assetsFlow(tokenSymbol: TokenSymbol): Flow> { + return interactor.receiveAssetFlow(tokenSymbol, externalBalancesFlow) + } + + override fun networkClicked(network: NetworkFlowRvItem) { + validate(network) { + router.openReceive(AssetPayload(network.chainId, network.assetId)) + } + } + + override fun getTitle(tokenSymbol: TokenSymbol): String { + return resourceManager.getString(R.string.receive_network_flow_title, tokenSymbol.value) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowComponent.kt new file mode 100644 index 0000000000..f2ca46e7b2 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowComponent.kt @@ -0,0 +1,30 @@ +package io.novafoundation.nova.feature_assets.presentation.receive.flow.network.di + +import androidx.fragment.app.Fragment +import dagger.BindsInstance +import dagger.Subcomponent +import io.novafoundation.nova.common.di.scope.ScreenScope +import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowFragment +import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_assets.presentation.receive.flow.network.NetworkReceiveFlowFragment + +@Subcomponent( + modules = [ + NetworkReceiveFlowModule::class + ] +) +@ScreenScope +interface NetworkReceiveFlowComponent { + + @Subcomponent.Factory + interface Factory { + + fun create( + @BindsInstance fragment: Fragment, + @BindsInstance networkFlowPayload: NetworkFlowPayload + ): NetworkReceiveFlowComponent + } + + fun inject(fragment: NetworkReceiveFlowFragment) +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowModule.kt new file mode 100644 index 0000000000..7bbec83925 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowModule.kt @@ -0,0 +1,55 @@ +package io.novafoundation.nova.feature_assets.presentation.receive.flow.network.di + +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import dagger.Module +import dagger.Provides +import dagger.multibindings.IntoMap +import io.novafoundation.nova.common.di.viewmodel.ViewModelKey +import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase +import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor +import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_assets.presentation.receive.flow.network.NetworkReceiveFlowViewModel +import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry + +@Module(includes = [ViewModelModule::class]) +class NetworkReceiveFlowModule { + + @Provides + internal fun provideViewModel(fragment: Fragment, factory: ViewModelProvider.Factory): NetworkReceiveFlowViewModel { + return ViewModelProvider(fragment, factory).get(NetworkReceiveFlowViewModel::class.java) + } + + @Provides + @IntoMap + @ViewModelKey(NetworkReceiveFlowViewModel::class) + fun provideViewModel( + interactor: AssetNetworksInteractor, + router: AssetsRouter, + externalBalancesInteractor: ExternalBalancesInteractor, + controllableAssetCheck: ControllableAssetCheckMixin, + accountUseCase: SelectedAccountUseCase, + resourceManager: ResourceManager, + networkFlowPayload: NetworkFlowPayload, + chainRegistry: ChainRegistry + ): ViewModel { + return NetworkReceiveFlowViewModel( + interactor = interactor, + router = router, + externalBalancesInteractor = externalBalancesInteractor, + controllableAssetCheck = controllableAssetCheck, + accountUseCase = accountUseCase, + resourceManager = resourceManager, + networkFlowPayload = networkFlowPayload, + chainRegistry = chainRegistry + ) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowFragment.kt similarity index 90% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowFragment.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowFragment.kt index 84ffd426f3..1fdee4dea1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowFragment.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.send.flow +package io.novafoundation.nova.feature_assets.presentation.send.flow.asset import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.feature_assets.R @@ -25,8 +25,4 @@ class AssetSendFlowFragment : AssetFlowFragment() { .create(this) .inject(this) } - - override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { - showMessage("Not implemented yet") - } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt similarity index 95% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt index 1d843b94b7..19363b2e1a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.send.flow +package io.novafoundation.nova.feature_assets.presentation.send.flow.asset import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.view.PlaceholderModel @@ -18,6 +18,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor @@ -54,6 +55,7 @@ class AssetSendFlowViewModel( } override fun tokenClicked(assetModel: TokenGroupUi) { + router.openSendNetworks(NetworkFlowPayload(assetModel.tokenSymbol)) } override fun mapNetworkAssets(assets: Map>, currency: Currency): List { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/di/AssetSendFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowComponent.kt similarity index 93% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/di/AssetSendFlowComponent.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowComponent.kt index 66314048dd..3f206c0621 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/di/AssetSendFlowComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowComponent.kt @@ -1,10 +1,10 @@ -package io.novafoundation.nova.feature_assets.presentation.send.flow.di +package io.novafoundation.nova.feature_assets.presentation.send.flow.asset.di import androidx.fragment.app.Fragment import dagger.BindsInstance import dagger.Subcomponent import io.novafoundation.nova.common.di.scope.ScreenScope -import io.novafoundation.nova.feature_assets.presentation.send.flow.AssetSendFlowFragment +import io.novafoundation.nova.feature_assets.presentation.send.flow.asset.AssetSendFlowFragment @Subcomponent( modules = [ diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/di/AssetSendFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt similarity index 97% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/di/AssetSendFlowModule.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt index 79ce136139..7fdf4bb8f1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/di/AssetSendFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.send.flow.di +package io.novafoundation.nova.feature_assets.presentation.send.flow.asset.di import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel @@ -14,7 +14,7 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.send.flow.AssetSendFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.send.flow.asset.AssetSendFlowViewModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor @Module(includes = [ViewModelModule::class]) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt new file mode 100644 index 0000000000..022708f829 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt @@ -0,0 +1,16 @@ +package io.novafoundation.nova.feature_assets.presentation.send.flow.network + +import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi +import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment + +class NetworkSendFlowFragment : NetworkFlowFragment() { + + override fun inject() { + FeatureUtils.getFeature(this, AssetsFeatureApi::class.java) + .networkSendFlowComponent() + .create(this, payload) + .inject(this) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt new file mode 100644 index 0000000000..606e1d2397 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt @@ -0,0 +1,59 @@ +package io.novafoundation.nova.feature_assets.presentation.send.flow.network + +import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.common.utils.TokenSymbol +import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase +import io.novafoundation.nova.feature_assets.R +import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor +import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.model.NetworkFlowRvItem +import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload +import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry +import kotlinx.coroutines.flow.Flow + +class NetworkSendFlowViewModel( + interactor: AssetNetworksInteractor, + router: AssetsRouter, + externalBalancesInteractor: ExternalBalancesInteractor, + controllableAssetCheck: ControllableAssetCheckMixin, + accountUseCase: SelectedAccountUseCase, + resourceManager: ResourceManager, + networkFlowPayload: NetworkFlowPayload, + chainRegistry: ChainRegistry +) : NetworkFlowViewModel( + interactor, + router, + controllableAssetCheck, + accountUseCase, + externalBalancesInteractor, + resourceManager, + networkFlowPayload, + chainRegistry +) { + + override fun getAssetBalance(asset: AssetWithNetwork): Amount { + return asset.balanceWithOffChain.transferable + } + + override fun assetsFlow(tokenSymbol: TokenSymbol): Flow> { + return interactor.sendAssetFlow(tokenSymbol, externalBalancesFlow) + } + + override fun networkClicked(network: NetworkFlowRvItem) { + validate(network) { + val assetPayload = AssetPayload(network.chainId, network.assetId) + router.openSend(SendPayload.SpecifiedOrigin(assetPayload)) + } + } + + override fun getTitle(tokenSymbol: TokenSymbol): String { + return resourceManager.getString(R.string.send_network_flow_title, tokenSymbol.value) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowComponent.kt new file mode 100644 index 0000000000..e70770238e --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowComponent.kt @@ -0,0 +1,30 @@ +package io.novafoundation.nova.feature_assets.presentation.send.flow.network.di + +import androidx.fragment.app.Fragment +import dagger.BindsInstance +import dagger.Subcomponent +import io.novafoundation.nova.common.di.scope.ScreenScope +import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowFragment +import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_assets.presentation.send.flow.network.NetworkSendFlowFragment + +@Subcomponent( + modules = [ + NetworkSendFlowModule::class + ] +) +@ScreenScope +interface NetworkSendFlowComponent { + + @Subcomponent.Factory + interface Factory { + + fun create( + @BindsInstance fragment: Fragment, + @BindsInstance networkFlowPayload: NetworkFlowPayload + ): NetworkSendFlowComponent + } + + fun inject(fragment: NetworkSendFlowFragment) +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowModule.kt new file mode 100644 index 0000000000..1327100678 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowModule.kt @@ -0,0 +1,55 @@ +package io.novafoundation.nova.feature_assets.presentation.send.flow.network.di + +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import dagger.Module +import dagger.Provides +import dagger.multibindings.IntoMap +import io.novafoundation.nova.common.di.viewmodel.ViewModelKey +import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase +import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor +import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_assets.presentation.send.flow.network.NetworkSendFlowViewModel +import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry + +@Module(includes = [ViewModelModule::class]) +class NetworkSendFlowModule { + + @Provides + internal fun provideViewModel(fragment: Fragment, factory: ViewModelProvider.Factory): NetworkSendFlowViewModel { + return ViewModelProvider(fragment, factory).get(NetworkSendFlowViewModel::class.java) + } + + @Provides + @IntoMap + @ViewModelKey(NetworkSendFlowViewModel::class) + fun provideViewModel( + interactor: AssetNetworksInteractor, + router: AssetsRouter, + externalBalancesInteractor: ExternalBalancesInteractor, + controllableAssetCheck: ControllableAssetCheckMixin, + accountUseCase: SelectedAccountUseCase, + resourceManager: ResourceManager, + networkFlowPayload: NetworkFlowPayload, + chainRegistry: ChainRegistry + ): ViewModel { + return NetworkSendFlowViewModel( + interactor = interactor, + router = router, + externalBalancesInteractor = externalBalancesInteractor, + controllableAssetCheck = controllableAssetCheck, + accountUseCase = accountUseCase, + resourceManager = resourceManager, + networkFlowPayload = networkFlowPayload, + chainRegistry = chainRegistry + ) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowFragment.kt similarity index 94% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowFragment.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowFragment.kt index c7b8140cfc..14187fa005 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowFragment.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.swap +package io.novafoundation.nova.feature_assets.presentation.swap.asset import android.os.Bundle import io.novafoundation.nova.common.di.FeatureUtils diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt similarity index 98% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index fece67d048..6bcd5139ce 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.swap +package io.novafoundation.nova.feature_assets.presentation.swap.asset import androidx.annotation.StringRes import androidx.lifecycle.viewModelScope diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/SwapFlowPayload.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/SwapFlowPayload.kt similarity index 91% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/SwapFlowPayload.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/SwapFlowPayload.kt index 6415528db8..8c77ce0465 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/SwapFlowPayload.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/SwapFlowPayload.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.swap +package io.novafoundation.nova.feature_assets.presentation.swap.asset import android.os.Parcelable import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowComponent.kt index 2163b3d2aa..e2be1a4349 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowComponent.kt @@ -4,8 +4,8 @@ import androidx.fragment.app.Fragment import dagger.BindsInstance import dagger.Subcomponent import io.novafoundation.nova.common.di.scope.ScreenScope -import io.novafoundation.nova.feature_assets.presentation.swap.AssetSwapFlowFragment -import io.novafoundation.nova.feature_assets.presentation.swap.SwapFlowPayload +import io.novafoundation.nova.feature_assets.presentation.swap.asset.AssetSwapFlowFragment +import io.novafoundation.nova.feature_assets.presentation.swap.asset.SwapFlowPayload @Subcomponent( modules = [ diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowModule.kt index 00cde3e117..bbe60c0c6e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowModule.kt @@ -14,8 +14,8 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.swap.AssetSwapFlowViewModel -import io.novafoundation.nova.feature_assets.presentation.swap.SwapFlowPayload +import io.novafoundation.nova.feature_assets.presentation.swap.asset.AssetSwapFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.swap.asset.SwapFlowPayload import io.novafoundation.nova.feature_assets.presentation.swap.executor.InitialSwapFlowExecutor import io.novafoundation.nova.feature_assets.presentation.swap.executor.SwapFlowExecutorFactory import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/SwapFlowExecutor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/SwapFlowExecutor.kt index 2bf30d9cf2..4b58983382 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/SwapFlowExecutor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/SwapFlowExecutor.kt @@ -1,7 +1,7 @@ package io.novafoundation.nova.feature_assets.presentation.swap.executor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter -import io.novafoundation.nova.feature_assets.presentation.swap.SwapFlowPayload +import io.novafoundation.nova.feature_assets.presentation.swap.asset.SwapFlowPayload import io.novafoundation.nova.feature_assets.presentation.swap.executor.ReselectSwapFlowExecutor.SelectingDirection import io.novafoundation.nova.feature_swap_api.presentation.state.SwapSettingsStateProvider import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt new file mode 100644 index 0000000000..709202a4be --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt @@ -0,0 +1,16 @@ +package io.novafoundation.nova.feature_assets.presentation.swap.network + +import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi +import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment + +class NetworkSwapFlowFragment : NetworkFlowFragment() { + + override fun inject() { + FeatureUtils.getFeature(this, AssetsFeatureApi::class.java) + .networkSwapFlowComponent() + .create(this, payload) + .inject(this) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt new file mode 100644 index 0000000000..e76a369c76 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt @@ -0,0 +1,59 @@ +package io.novafoundation.nova.feature_assets.presentation.swap.network + +import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.common.utils.TokenSymbol +import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase +import io.novafoundation.nova.feature_assets.R +import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor +import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.model.NetworkFlowRvItem +import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload +import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry +import kotlinx.coroutines.flow.Flow + +class NetworkSwapFlowViewModel( + interactor: AssetNetworksInteractor, + router: AssetsRouter, + externalBalancesInteractor: ExternalBalancesInteractor, + controllableAssetCheck: ControllableAssetCheckMixin, + accountUseCase: SelectedAccountUseCase, + resourceManager: ResourceManager, + networkFlowPayload: NetworkFlowPayload, + chainRegistry: ChainRegistry +) : NetworkFlowViewModel( + interactor, + router, + controllableAssetCheck, + accountUseCase, + externalBalancesInteractor, + resourceManager, + networkFlowPayload, + chainRegistry +) { + + override fun getAssetBalance(asset: AssetWithNetwork): Amount { + return asset.balanceWithOffChain.transferable + } + + override fun assetsFlow(tokenSymbol: TokenSymbol): Flow> { + return interactor.sendAssetFlow(tokenSymbol, externalBalancesFlow) + } + + override fun networkClicked(network: NetworkFlowRvItem) { + validate(network) { + val assetPayload = AssetPayload(network.chainId, network.assetId) + router.openSend(SendPayload.SpecifiedOrigin(assetPayload)) + } + } + + override fun getTitle(tokenSymbol: TokenSymbol): String { + return resourceManager.getString(R.string.send_network_flow_title, tokenSymbol.value) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowComponent.kt new file mode 100644 index 0000000000..82df8c6688 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowComponent.kt @@ -0,0 +1,31 @@ +package io.novafoundation.nova.feature_assets.presentation.swap.network.di + +import androidx.fragment.app.Fragment +import dagger.BindsInstance +import dagger.Subcomponent +import io.novafoundation.nova.common.di.scope.ScreenScope +import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowFragment +import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_assets.presentation.send.flow.network.NetworkSendFlowFragment +import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowFragment + +@Subcomponent( + modules = [ + NetworkSwapFlowModule::class + ] +) +@ScreenScope +interface NetworkSwapFlowComponent { + + @Subcomponent.Factory + interface Factory { + + fun create( + @BindsInstance fragment: Fragment, + @BindsInstance networkFlowPayload: NetworkFlowPayload + ): NetworkSwapFlowComponent + } + + fun inject(fragment: NetworkSwapFlowFragment) +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowModule.kt new file mode 100644 index 0000000000..3e18ccbe93 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowModule.kt @@ -0,0 +1,56 @@ +package io.novafoundation.nova.feature_assets.presentation.swap.network.di + +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import dagger.Module +import dagger.Provides +import dagger.multibindings.IntoMap +import io.novafoundation.nova.common.di.viewmodel.ViewModelKey +import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase +import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor +import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor +import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_assets.presentation.send.flow.network.NetworkSendFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowViewModel +import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry + +@Module(includes = [ViewModelModule::class]) +class NetworkSwapFlowModule { + + @Provides + internal fun provideViewModel(fragment: Fragment, factory: ViewModelProvider.Factory): NetworkSwapFlowViewModel { + return ViewModelProvider(fragment, factory).get(NetworkSwapFlowViewModel::class.java) + } + + @Provides + @IntoMap + @ViewModelKey(NetworkSwapFlowViewModel::class) + fun provideViewModel( + interactor: AssetNetworksInteractor, + router: AssetsRouter, + externalBalancesInteractor: ExternalBalancesInteractor, + controllableAssetCheck: ControllableAssetCheckMixin, + accountUseCase: SelectedAccountUseCase, + resourceManager: ResourceManager, + networkFlowPayload: NetworkFlowPayload, + chainRegistry: ChainRegistry + ): ViewModel { + return NetworkSwapFlowViewModel( + interactor = interactor, + router = router, + externalBalancesInteractor = externalBalancesInteractor, + controllableAssetCheck = controllableAssetCheck, + accountUseCase = accountUseCase, + resourceManager = resourceManager, + networkFlowPayload = networkFlowPayload, + chainRegistry = chainRegistry + ) + } +} From 5113e518c1ec12ecac5bf73ab4f31baae6dd5c33 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 25 Oct 2024 10:05:35 +0200 Subject: [PATCH 20/78] Swap flow + bug fixes --- .../nova/app/root/navigation/Navigator.kt | 18 ++++++++------- .../main/res/navigation/main_nav_graph.xml | 21 ++++++++++++++--- .../nova/common/utils/FlowExt.kt | 4 ++++ .../nova/common/utils/KEY_PAYLOAD.kt | 1 - .../nova/common/utils/KotlinExt.kt | 5 ++++ common/src/main/res/values/strings.xml | 1 + .../di/AssetsFeatureComponent.kt | 2 +- .../feature_assets/di/AssetsFeatureModule.kt | 20 ++++++++++++++++ .../assets/models/AssetFlowSearchResult.kt | 7 +++--- .../assets/search/AssetSearchInteractor.kt | 8 +++---- .../networks/AssetNetworksInteractor.kt | 22 ++++++++++-------- .../presentation/AssetsRouter.kt | 9 ++++---- .../balance/list/BalanceListFragment.kt | 2 +- .../balance/list/model/items/TokenGroupUi.kt | 2 +- .../buy/flow/asset/AssetBuyFlowFragment.kt | 1 - .../buy/flow/asset/AssetBuyFlowViewModel.kt | 7 ++++-- .../flow/network/NetworkBuyFlowFragment.kt | 9 ++++---- .../flow/network/NetworkBuyFlowViewModel.kt | 8 ++++--- .../network/di/NetworkBuyFlowComponent.kt | 1 - .../flow/asset/AssetFlowViewModel.kt | 11 +++++---- .../flow/network/NetworkFlowFragment.kt | 4 ---- .../flow/network/NetworkFlowViewModel.kt | 1 - .../flow/asset/AssetReceiveFlowViewModel.kt | 12 ++++++---- .../network/NetworkReceiveFlowFragment.kt | 6 ++++- .../network/di/NetworkReceiveFlowComponent.kt | 2 -- .../network/di/NetworkReceiveFlowModule.kt | 2 -- .../send/flow/asset/AssetSendFlowFragment.kt | 1 - .../send/flow/asset/AssetSendFlowViewModel.kt | 15 ++++++++---- .../flow/network/NetworkSendFlowFragment.kt | 6 ++++- .../flow/network/NetworkSendFlowViewModel.kt | 6 ++--- .../network/di/NetworkSendFlowComponent.kt | 2 -- .../flow/network/di/NetworkSendFlowModule.kt | 2 -- .../swap/asset/AssetSwapFlowFragment.kt | 5 ---- .../swap/asset/AssetSwapFlowViewModel.kt | 23 +++++++++++++------ .../{ => asset}/di/AssetSwapFlowComponent.kt | 2 +- .../{ => asset}/di/AssetSwapFlowModule.kt | 22 ++---------------- .../swap/network/NetworkSwapFlowFragment.kt | 9 +++++++- .../swap/network/NetworkSwapFlowPayload.kt | 12 ++++++++++ .../swap/network/NetworkSwapFlowViewModel.kt | 18 ++++++++------- .../network/di/NetworkSwapFlowComponent.kt | 7 ++---- .../swap/network/di/NetworkSwapFlowModule.kt | 14 +++++------ .../main/SwapMainSettingsViewModel.kt | 2 ++ 42 files changed, 197 insertions(+), 135 deletions(-) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/{ => asset}/di/AssetSwapFlowComponent.kt (98%) rename feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/{ => asset}/di/AssetSwapFlowModule.kt (78%) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowPayload.kt diff --git a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt index 4fd0208578..530e524344 100644 --- a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt +++ b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt @@ -62,6 +62,8 @@ import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayloa import io.novafoundation.nova.feature_assets.presentation.send.confirm.ConfirmSendFragment import io.novafoundation.nova.feature_assets.presentation.swap.asset.AssetSwapFlowFragment import io.novafoundation.nova.feature_assets.presentation.swap.asset.SwapFlowPayload +import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowFragment +import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowPayload import io.novafoundation.nova.feature_assets.presentation.tokens.add.enterInfo.AddTokenEnterInfoFragment import io.novafoundation.nova.feature_assets.presentation.tokens.add.enterInfo.AddTokenEnterInfoPayload import io.novafoundation.nova.feature_assets.presentation.tokens.manage.chain.ManageChainTokensFragment @@ -385,20 +387,20 @@ class Navigator( navController?.navigate(R.id.action_close_send_flow) } - override fun openSendNetworks(networkFlowPayload: NetworkFlowPayload) { - navController?.navigate(R.id.action_sendFlow_to_sendFlowNetwork, NetworkFlowFragment.createPayload(networkFlowPayload)) + override fun openSendNetworks(payload: NetworkFlowPayload) { + navController?.navigate(R.id.action_sendFlow_to_sendFlowNetwork, NetworkFlowFragment.createPayload(payload)) } - override fun openReceiveNetworks(networkFlowPayload: NetworkFlowPayload) { - navController?.navigate(R.id.action_receiveFlow_to_receiveFlowNetwork, NetworkFlowFragment.createPayload(networkFlowPayload)) + override fun openReceiveNetworks(payload: NetworkFlowPayload) { + navController?.navigate(R.id.action_receiveFlow_to_receiveFlowNetwork, NetworkFlowFragment.createPayload(payload)) } - override fun openSwapNetworks(networkFlowPayload: NetworkFlowPayload) { - TODO("Not yet implemented") + override fun openSwapNetworks(payload: NetworkSwapFlowPayload) { + navController?.navigate(R.id.action_swapFlow_to_swapFlowNetwork, NetworkSwapFlowFragment.createPayload(payload)) } - override fun openBuyNetworks(networkFlowPayload: NetworkFlowPayload) { - navController?.navigate(R.id.action_buyFlow_to_buyFlowNetwork, NetworkFlowFragment.createPayload(networkFlowPayload)) + override fun openBuyNetworks(payload: NetworkFlowPayload) { + navController?.navigate(R.id.action_buyFlow_to_buyFlowNetwork, NetworkFlowFragment.createPayload(payload)) } override fun openSwapFlow() { diff --git a/app/src/main/res/navigation/main_nav_graph.xml b/app/src/main/res/navigation/main_nav_graph.xml index fec0a2f29f..48aff339f2 100644 --- a/app/src/main/res/navigation/main_nav_graph.xml +++ b/app/src/main/res/navigation/main_nav_graph.xml @@ -923,6 +923,21 @@ + + + + + + + android:id="@+id/swapFlowNetworkFragment" + android:name="io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowFragment" + android:label="NetworkBuyFlowFragment" /> Flow>.filterList(crossinline handler: suspend (T) -> Bool list.filter { item -> handler(item) } } +inline fun Flow>.filterSet(crossinline handler: suspend (T) -> Boolean) = map { set -> + set.filter { item -> handler(item) }.toSet() +} + inline fun Flow>.mapList(crossinline mapper: suspend (T) -> R) = map { list -> list.map { item -> mapper(item) } } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/KEY_PAYLOAD.kt b/common/src/main/java/io/novafoundation/nova/common/utils/KEY_PAYLOAD.kt index 6eabdc3f59..2201168910 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/KEY_PAYLOAD.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/KEY_PAYLOAD.kt @@ -32,5 +32,4 @@ interface FragmentPayloadHolder : PayloadHolder { require(this is Fragment) return requireArguments().getParcelable(KEY_PAYLOAD)!! } - } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/KotlinExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/KotlinExt.kt index 4717260d45..c6e87dfe0e 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/KotlinExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/KotlinExt.kt @@ -23,6 +23,7 @@ import java.util.Collections import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit +import kotlinx.coroutines.launch import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -597,3 +598,7 @@ fun Calendar.resetDay() { set(Calendar.SECOND, 0) set(Calendar.MILLISECOND, 0) } + +inline fun CoroutineScope.launchUnit(crossinline block: suspend CoroutineScope.() -> Unit) { + launch { block() } +} diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index a2ca2b36b0..ebda8576ce 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -4,6 +4,7 @@ Select network for buying %s Select network for receiving %s Select network for sending %s + Select network for swaping %s Tokens Networks diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt index 693d51ccbc..059d7d2f94 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureComponent.kt @@ -21,7 +21,7 @@ import io.novafoundation.nova.feature_assets.presentation.send.amount.di.SelectS import io.novafoundation.nova.feature_assets.presentation.send.confirm.di.ConfirmSendComponent import io.novafoundation.nova.feature_assets.presentation.send.flow.asset.di.AssetSendFlowComponent import io.novafoundation.nova.feature_assets.presentation.send.flow.network.di.NetworkSendFlowComponent -import io.novafoundation.nova.feature_assets.presentation.swap.di.AssetSwapFlowComponent +import io.novafoundation.nova.feature_assets.presentation.swap.asset.di.AssetSwapFlowComponent import io.novafoundation.nova.feature_assets.presentation.swap.network.di.NetworkSwapFlowComponent import io.novafoundation.nova.feature_assets.presentation.tokens.add.enterInfo.di.AddTokenEnterInfoComponent import io.novafoundation.nova.feature_assets.presentation.tokens.add.selectChain.di.AddTokenSelectChainComponent diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt index 6c30ec902a..62aff76073 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt @@ -26,13 +26,17 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.assets.RealExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor +import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.swap.executor.InitialSwapFlowExecutor +import io.novafoundation.nova.feature_assets.presentation.swap.executor.SwapFlowExecutorFactory import io.novafoundation.nova.feature_assets.presentation.transaction.filter.HistoryFiltersProviderFactory import io.novafoundation.nova.feature_currency_api.domain.interfaces.CurrencyRepository import io.novafoundation.nova.feature_nft_api.data.repository.NftRepository import io.novafoundation.nova.feature_staking_api.data.network.blockhain.updaters.PooledBalanceUpdaterFactory import io.novafoundation.nova.feature_staking_api.data.nominationPools.pool.PoolAccountDerivation import io.novafoundation.nova.feature_swap_api.domain.swap.SwapService +import io.novafoundation.nova.feature_swap_api.presentation.state.SwapSettingsStateProvider import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.AssetSourceRegistry import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.updaters.BalanceLocksUpdaterFactory import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.updaters.PaymentUpdaterFactory @@ -152,4 +156,20 @@ class AssetsFeatureModule { coinPriceRepository = coinPriceRepository, poolAccountDerivation = poolAccountDerivation ) + + @Provides + fun provideInitialSwapFlowExecutor( + assetsRouter: AssetsRouter + ): InitialSwapFlowExecutor { + return InitialSwapFlowExecutor(assetsRouter) + } + + @Provides + fun provideSwapExecutor( + initialSwapFlowExecutor: InitialSwapFlowExecutor, + assetsRouter: AssetsRouter, + swapSettingsStateProvider: SwapSettingsStateProvider + ): SwapFlowExecutorFactory { + return SwapFlowExecutorFactory(initialSwapFlowExecutor, assetsRouter, swapSettingsStateProvider) + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt index 08a6c754bc..724d4686cf 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_assets.domain.assets.models +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup @@ -8,12 +9,12 @@ sealed interface AssetFlowSearchResult { class ByNetworks(val assets: Map>) : AssetFlowSearchResult - class ByTokens(val tokens: List) : AssetFlowSearchResult + class ByTokens(val tokens: Map>) : AssetFlowSearchResult } -fun AssetFlowSearchResult.toList(): List { +fun AssetFlowSearchResult.groupList(): List { return when (this) { is AssetFlowSearchResult.ByNetworks -> assets.keys.toList() - is AssetFlowSearchResult.ByTokens -> tokens + is AssetFlowSearchResult.ByTokens -> tokens.keys.toList() } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt index 5fd2e0f79d..68024957a7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt @@ -57,7 +57,7 @@ class AssetSearchInteractor( .map { AssetFlowSearchResult.ByNetworks(it) } AssetViewMode.TOKENS -> searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = filter) - .map { AssetFlowSearchResult.ByTokens(it.keys.toList()) } + .map { AssetFlowSearchResult.ByTokens(it) } } } } @@ -85,7 +85,7 @@ class AssetSearchInteractor( assetsComparator = getTokenAssetBaseComparator { it.balanceWithOffChain.transferable.fiat }, filter = filter ) - .map { AssetFlowSearchResult.ByTokens(it.keys.toList()) } + .map { AssetFlowSearchResult.ByTokens(it) } } } } @@ -112,7 +112,7 @@ class AssetSearchInteractor( .map { AssetFlowSearchResult.ByNetworks(it) } AssetViewMode.TOKENS -> searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filterFlow = filterFlow) - .map { AssetFlowSearchResult.ByTokens(it.keys.toList()) } + .map { AssetFlowSearchResult.ByTokens(it) } } } } @@ -127,7 +127,7 @@ class AssetSearchInteractor( .map { AssetFlowSearchResult.ByNetworks(it) } AssetViewMode.TOKENS -> searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = null) - .map { AssetFlowSearchResult.ByTokens(it.keys.toList()) } + .map { AssetFlowSearchResult.ByTokens(it) } } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt index a812e26a2b..f297c6a6e1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.feature_assets.domain.networks import io.novafoundation.nova.common.utils.TokenSymbol import io.novafoundation.nova.common.utils.filterList +import io.novafoundation.nova.common.utils.filterSet import io.novafoundation.nova.common.utils.flowOfAll import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork @@ -23,6 +24,7 @@ import io.novasama.substrate_sdk_android.hash.isPositive import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map @@ -61,12 +63,11 @@ class AssetNetworksInteractor( } fun swapAssetsFlow( - forAsset: FullChainAssetId?, tokenSymbol: TokenSymbol, externalBalancesFlow: Flow>, coroutineScope: CoroutineScope ): Flow> { - val filterFlow = getAvailableSwapAssets(forAsset, coroutineScope).map { availableAssetsForSwap -> + val filterFlow = getAvailableSwapAssets(tokenSymbol, coroutineScope).map { availableAssetsForSwap -> val filter: AssetFilter = { asset -> val chainAsset = asset.token.configuration @@ -119,15 +120,16 @@ class AssetNetworksInteractor( } } - private fun getAvailableSwapAssets(asset: FullChainAssetId?, coroutineScope: CoroutineScope): Flow> { + private fun getAvailableSwapAssets(tokenSymbol: TokenSymbol, coroutineScope: CoroutineScope): Flow> { return flowOfAll { - val chainAsset = asset?.let { chainRegistry.asset(it) } - - if (chainAsset == null) { - swapService.assetsAvailableForSwap(coroutineScope) - } else { - swapService.availableSwapDirectionsFor(chainAsset, coroutineScope) - } + val chains = chainRegistry.enabledChainById() + .filter { (_, chain) -> + // Take only chains that have target asset + chain.assets.any { it.symbol == tokenSymbol } + } + + swapService.assetsAvailableForSwap(coroutineScope) + .filterSet { it.chainId in chains.keys } } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt index e2a19334a1..8c1be6cfeb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt @@ -5,6 +5,7 @@ import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFl import io.novafoundation.nova.feature_assets.presentation.model.OperationParcelizeModel import io.novafoundation.nova.feature_assets.presentation.send.TransferDraft import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload +import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowPayload import io.novafoundation.nova.feature_assets.presentation.tokens.add.enterInfo.AddTokenEnterInfoPayload import io.novafoundation.nova.feature_assets.presentation.tokens.manage.chain.ManageChainTokensPayload import io.novafoundation.nova.feature_assets.presentation.transaction.filter.TransactionHistoryFilterPayload @@ -75,11 +76,11 @@ interface AssetsRouter { fun closeSendFlow() - fun openSendNetworks(networkFlowPayload: NetworkFlowPayload) + fun openSendNetworks(payload: NetworkFlowPayload) - fun openReceiveNetworks(networkFlowPayload: NetworkFlowPayload) + fun openReceiveNetworks(payload: NetworkFlowPayload) - fun openSwapNetworks(networkFlowPayload: NetworkFlowPayload) + fun openSwapNetworks(payload: NetworkSwapFlowPayload) - fun openBuyNetworks(networkFlowPayload: NetworkFlowPayload) + fun openBuyNetworks(payload: NetworkFlowPayload) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index d7878b5eeb..d85863cc68 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -148,7 +148,7 @@ class BalanceListFragment : override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { if (tokenGroup.groupType is TokenGroupUi.GroupType.SingleItem) { - viewModel.assetClicked(tokenGroup.groupType.item) + viewModel.assetClicked(tokenGroup.groupType.asset) } else { val itemAnimator = balanceListAssets.itemAnimator as AssetTokensItemAnimator itemAnimator.prepareForAnimation() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt index a3fddfd53f..6adbd9b5c7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt @@ -20,6 +20,6 @@ data class TokenGroupUi( sealed interface GroupType { object Group : GroupType - data class SingleItem(val item: AssetModel) : GroupType + data class SingleItem(val asset: AssetModel) : GroupType } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowFragment.kt index 400b8b0843..b3a10a76b0 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowFragment.kt @@ -4,7 +4,6 @@ import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent -import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowFragment import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixinUi import javax.inject.Inject diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt index 0003f11513..df2c280bc6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt @@ -47,7 +47,10 @@ class AssetBuyFlowViewModel( } } - override fun tokenClicked(assetModel: TokenGroupUi) { - router.openBuyNetworks(NetworkFlowPayload(assetModel.tokenSymbol)) + override fun tokenClicked(tokenGroup: TokenGroupUi) { + when (val type = tokenGroup.groupType) { + is TokenGroupUi.GroupType.SingleItem -> assetClicked(type.asset) + TokenGroupUi.GroupType.Group -> router.openBuyNetworks(NetworkFlowPayload(tokenGroup.tokenSymbol)) + } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt index 8f381492e5..df0164065a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt @@ -1,16 +1,17 @@ package io.novafoundation.nova.feature_assets.presentation.buy.flow.network import io.novafoundation.nova.common.di.FeatureUtils -import io.novafoundation.nova.feature_assets.R +import io.novafoundation.nova.common.utils.FragmentPayloadHolder import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent -import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi -import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowFragment import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixinUi import javax.inject.Inject -class NetworkBuyFlowFragment : NetworkFlowFragment() { +class NetworkBuyFlowFragment : + NetworkFlowFragment(), + FragmentPayloadHolder { @Inject lateinit var buyMixin: BuyMixinUi diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt index 92b8063933..d5aa48e258 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt @@ -51,9 +51,11 @@ class NetworkBuyFlowViewModel( } override fun networkClicked(network: NetworkFlowRvItem) { - launch { - val chainAsset = chainRegistry.asset(network.chainId, network.assetId) - buyMixin.buyClicked(chainAsset) + validate(network) { + launch { + val chainAsset = chainRegistry.asset(network.chainId, network.assetId) + buyMixin.buyClicked(chainAsset) + } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowComponent.kt index 754b9a018a..f24d0a50a3 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/di/NetworkBuyFlowComponent.kt @@ -4,7 +4,6 @@ import androidx.fragment.app.Fragment import dagger.BindsInstance import dagger.Subcomponent import io.novafoundation.nova.common.di.scope.ScreenScope -import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowFragment import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowFragment import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index 5fc4efb4a5..ec601f43a6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -9,8 +9,9 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAcco import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult -import io.novafoundation.nova.feature_assets.domain.assets.models.toList +import io.novafoundation.nova.feature_assets.domain.assets.models.groupList import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup @@ -61,7 +62,7 @@ abstract class AssetFlowViewModel( }.distinctUntilChanged() .shareInBackground(SharingStarted.Lazily) - val placeholder = searchAssetsFlow.map { getPlaceholder(query.value, it.toList()) } + val placeholder = searchAssetsFlow.map { getPlaceholder(query.value, it.groupList()) } fun backClicked() { router.back() @@ -71,7 +72,7 @@ abstract class AssetFlowViewModel( abstract fun assetClicked(assetModel: AssetModel) - abstract fun tokenClicked(assetModel: TokenGroupUi) + abstract fun tokenClicked(tokenGroup: TokenGroupUi) private fun mapAssets(searchResult: AssetFlowSearchResult, currency: Currency): List { return when (searchResult) { @@ -84,8 +85,8 @@ abstract class AssetFlowViewModel( return assets.mapGroupedAssetsToUi(currency) } - open fun mapTokensAssets(assets: List): List { - return assets.map { mapAssetGroupToUi(it, assets = emptyList()) } + open fun mapTokensAssets(assets: Map>): List { + return assets.map { mapAssetGroupToUi(it.key, assets = it.value) } } internal fun validate(assetModel: AssetModel, onAccept: (AssetModel) -> Unit) { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt index d774f6ba9f..5ba9c9e691 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowFragment.kt @@ -4,12 +4,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.annotation.StringRes import androidx.recyclerview.widget.ConcatAdapter import coil.ImageLoader import io.novafoundation.nova.common.base.BaseFragment import io.novafoundation.nova.common.utils.FragmentPayloadCreator -import io.novafoundation.nova.common.utils.FragmentPayloadHolder import io.novafoundation.nova.common.utils.PayloadCreator import io.novafoundation.nova.common.utils.applyStatusBarInsets import io.novafoundation.nova.common.view.recyclerview.adapter.text.TextAdapter @@ -17,13 +15,11 @@ import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.flow.network.model.NetworkFlowRvItem import io.novafoundation.nova.feature_assets.presentation.receive.view.LedgerNotSupportedWarningBottomSheet import javax.inject.Inject -import kotlinx.android.synthetic.main.fragment_asset_flow_search.assetFlowToolbar import kotlinx.android.synthetic.main.fragment_network_flow.networkFlowList import kotlinx.android.synthetic.main.fragment_network_flow.networkFlowToolbar abstract class NetworkFlowFragment : BaseFragment(), - FragmentPayloadHolder, NetworkFlowAdapter.ItemNetworkHandler { companion object : PayloadCreator by FragmentPayloadCreator() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt index 9397da2687..f7e873eb27 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt @@ -12,7 +12,6 @@ import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksIntera import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.flow.network.model.NetworkFlowRvItem -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_wallet_api.presentation.model.mapAmountToAmountModel import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry import io.novafoundation.nova.runtime.multiNetwork.asset diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt index e5a621b90f..309a023e52 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt @@ -42,13 +42,17 @@ class AssetReceiveFlowViewModel( } } - override fun tokenClicked(assetModel: TokenGroupUi) { - router.openReceiveNetworks(NetworkFlowPayload(assetModel.tokenSymbol)) + override fun tokenClicked(tokenGroup: TokenGroupUi) { + when (val type = tokenGroup.groupType) { + is TokenGroupUi.GroupType.SingleItem -> assetClicked(type.asset) + + TokenGroupUi.GroupType.Group -> router.openReceiveNetworks(NetworkFlowPayload(tokenGroup.tokenSymbol)) + } } private fun openNextScreen(assetModel: AssetModel) { val chainAsset = assetModel.token.configuration - val assePayload = AssetPayload(chainAsset.chainId, chainAsset.id) - router.openReceive(assePayload) + val assetPayload = AssetPayload(chainAsset.chainId, chainAsset.id) + router.openReceive(assetPayload) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt index 5d23c1e35a..75aeabdadf 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt @@ -1,11 +1,15 @@ package io.novafoundation.nova.feature_assets.presentation.receive.flow.network import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.common.utils.FragmentPayloadHolder import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload -class NetworkReceiveFlowFragment : NetworkFlowFragment() { +class NetworkReceiveFlowFragment : + NetworkFlowFragment(), + FragmentPayloadHolder { override fun inject() { FeatureUtils.getFeature(this, AssetsFeatureApi::class.java) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowComponent.kt index f2ca46e7b2..4f680b0ce1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowComponent.kt @@ -4,8 +4,6 @@ import androidx.fragment.app.Fragment import dagger.BindsInstance import dagger.Subcomponent import io.novafoundation.nova.common.di.scope.ScreenScope -import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowFragment -import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowFragment import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.receive.flow.network.NetworkReceiveFlowFragment diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowModule.kt index 7bbec83925..326185c0bd 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/di/NetworkReceiveFlowModule.kt @@ -14,10 +14,8 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowViewModel import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.receive.flow.network.NetworkReceiveFlowViewModel -import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry @Module(includes = [ViewModelModule::class]) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowFragment.kt index 1fdee4dea1..d1777f17c2 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowFragment.kt @@ -4,7 +4,6 @@ import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent -import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowFragment import kotlinx.android.synthetic.main.fragment_asset_flow_search.assetFlowPlaceholder diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt index 19363b2e1a..11647538f9 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt @@ -7,6 +7,7 @@ import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup @@ -54,17 +55,21 @@ class AssetSendFlowViewModel( router.openSend(SendPayload.SpecifiedOrigin(assetPayload)) } - override fun tokenClicked(assetModel: TokenGroupUi) { - router.openSendNetworks(NetworkFlowPayload(assetModel.tokenSymbol)) + override fun tokenClicked(tokenGroup: TokenGroupUi) { + when (val type = tokenGroup.groupType) { + is TokenGroupUi.GroupType.SingleItem -> assetClicked(type.asset) + + TokenGroupUi.GroupType.Group -> router.openSendNetworks(NetworkFlowPayload(tokenGroup.tokenSymbol)) + } } override fun mapNetworkAssets(assets: Map>, currency: Currency): List { return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, TotalAndTransferableBalance::transferable) } - override fun mapTokensAssets(assets: List): List { - return assets.map { - mapAssetGroupToUi(it, assets = emptyList()) { it.groupBalance.transferable } + override fun mapTokensAssets(assets: Map>): List { + return assets.map { (group, assets) -> + mapAssetGroupToUi(group, assets = assets) { it.groupBalance.transferable } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt index 022708f829..5f393d3e10 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt @@ -1,11 +1,15 @@ package io.novafoundation.nova.feature_assets.presentation.send.flow.network import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.common.utils.FragmentPayloadHolder import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload -class NetworkSendFlowFragment : NetworkFlowFragment() { +class NetworkSendFlowFragment : + NetworkFlowFragment(), + FragmentPayloadHolder { override fun inject() { FeatureUtils.getFeature(this, AssetsFeatureApi::class.java) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt index 606e1d2397..8187558da9 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt @@ -47,10 +47,8 @@ class NetworkSendFlowViewModel( } override fun networkClicked(network: NetworkFlowRvItem) { - validate(network) { - val assetPayload = AssetPayload(network.chainId, network.assetId) - router.openSend(SendPayload.SpecifiedOrigin(assetPayload)) - } + val assetPayload = AssetPayload(network.chainId, network.assetId) + router.openSend(SendPayload.SpecifiedOrigin(assetPayload)) } override fun getTitle(tokenSymbol: TokenSymbol): String { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowComponent.kt index e70770238e..d67d7cd930 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowComponent.kt @@ -4,8 +4,6 @@ import androidx.fragment.app.Fragment import dagger.BindsInstance import dagger.Subcomponent import io.novafoundation.nova.common.di.scope.ScreenScope -import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowFragment -import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowFragment import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.send.flow.network.NetworkSendFlowFragment diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowModule.kt index 1327100678..e20a497bea 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/di/NetworkSendFlowModule.kt @@ -14,10 +14,8 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowViewModel import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.send.flow.network.NetworkSendFlowViewModel -import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry @Module(includes = [ViewModelModule::class]) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowFragment.kt index 14187fa005..7837929571 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent -import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowFragment class AssetSwapFlowFragment : AssetFlowFragment() { @@ -31,8 +30,4 @@ class AssetSwapFlowFragment : AssetFlowFragment() { .create(this, argument(KEY_PAYLOAD)) .inject(this) } - - override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { - showMessage("Not implemented yet") - } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index 6bcd5139ce..275cfa43bb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -3,11 +3,13 @@ package io.novafoundation.nova.feature_assets.presentation.swap.asset import androidx.annotation.StringRes import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.common.utils.launchUnit import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup @@ -19,8 +21,10 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.swap.executor.SwapFlowExecutor +import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowPayload import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_swap_api.domain.interactor.SwapAvailabilityInteractor @@ -38,7 +42,7 @@ class AssetSwapFlowViewModel( resourceManager: ResourceManager, private val swapAvailabilityInteractor: SwapAvailabilityInteractor, private val swapFlowExecutor: SwapFlowExecutor, - private val payload: SwapFlowPayload + private val swapPayload: SwapFlowPayload ) : AssetFlowViewModel( interactor, router, @@ -57,7 +61,7 @@ class AssetSwapFlowViewModel( @StringRes fun getTitleRes(): Int { - return when (payload) { + return when (swapPayload) { SwapFlowPayload.InitialSelecting, is SwapFlowPayload.ReselectAssetIn -> R.string.assets_swap_flow_pay_title is SwapFlowPayload.ReselectAssetOut -> R.string.assets_swap_flow_receive_title } @@ -65,7 +69,7 @@ class AssetSwapFlowViewModel( override fun searchAssetsFlow(): Flow { return interactor.searchSwapAssetsFlow( - forAsset = payload.constraintDirectionsAsset?.fullChainAssetId, + forAsset = swapPayload.constraintDirectionsAsset?.fullChainAssetId, queryFlow = query, externalBalancesFlow = externalBalancesFlow, coroutineScope = viewModelScope @@ -79,16 +83,21 @@ class AssetSwapFlowViewModel( } } - override fun tokenClicked(assetModel: TokenGroupUi) { + override fun tokenClicked(tokenGroup: TokenGroupUi) = launchUnit { + when (val type = tokenGroup.groupType) { + is TokenGroupUi.GroupType.SingleItem -> assetClicked(type.asset) + + TokenGroupUi.GroupType.Group -> router.openSwapNetworks(NetworkSwapFlowPayload(NetworkFlowPayload(tokenGroup.tokenSymbol), swapPayload)) + } } override fun mapNetworkAssets(assets: Map>, currency: Currency): List { return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, TotalAndTransferableBalance::transferable) } - override fun mapTokensAssets(assets: List): List { - return assets.map { - mapAssetGroupToUi(it, assets = emptyList()) { it.groupBalance.transferable } + override fun mapTokensAssets(assets: Map>): List { + return assets.map { (group, assets) -> + mapAssetGroupToUi(group, assets = assets) { it.groupBalance.transferable } } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowComponent.kt similarity index 98% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowComponent.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowComponent.kt index e2be1a4349..02ad36b191 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowComponent.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.swap.di +package io.novafoundation.nova.feature_assets.presentation.swap.asset.di import androidx.fragment.app.Fragment import dagger.BindsInstance diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt similarity index 78% rename from feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowModule.kt rename to feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt index bbe60c0c6e..3ee24a13bf 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/di/AssetSwapFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt @@ -1,4 +1,4 @@ -package io.novafoundation.nova.feature_assets.presentation.swap.di +package io.novafoundation.nova.feature_assets.presentation.swap.asset.di import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel @@ -16,31 +16,13 @@ import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.swap.asset.AssetSwapFlowViewModel import io.novafoundation.nova.feature_assets.presentation.swap.asset.SwapFlowPayload -import io.novafoundation.nova.feature_assets.presentation.swap.executor.InitialSwapFlowExecutor import io.novafoundation.nova.feature_assets.presentation.swap.executor.SwapFlowExecutorFactory import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_swap_api.domain.interactor.SwapAvailabilityInteractor -import io.novafoundation.nova.feature_swap_api.presentation.state.SwapSettingsStateProvider @Module(includes = [ViewModelModule::class]) class AssetSwapFlowModule { - @Provides - fun provideInitialSwapFlowExecutor( - assetsRouter: AssetsRouter - ): InitialSwapFlowExecutor { - return InitialSwapFlowExecutor(assetsRouter) - } - - @Provides - fun provideSwapExecutor( - initialSwapFlowExecutor: InitialSwapFlowExecutor, - assetsRouter: AssetsRouter, - swapSettingsStateProvider: SwapSettingsStateProvider - ): SwapFlowExecutorFactory { - return SwapFlowExecutorFactory(initialSwapFlowExecutor, assetsRouter, swapSettingsStateProvider) - } - @Provides internal fun provideViewModel(fragment: Fragment, factory: ViewModelProvider.Factory): AssetSwapFlowViewModel { return ViewModelProvider(fragment, factory).get(AssetSwapFlowViewModel::class.java) @@ -70,7 +52,7 @@ class AssetSwapFlowModule { accountUseCase = accountUseCase, resourceManager = resourceManager, swapFlowExecutor = executorFactory.create(payload), - payload = payload, + swapPayload = payload, swapAvailabilityInteractor = swapAvailabilityInteractor ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt index 709202a4be..362d893a67 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt @@ -1,11 +1,18 @@ package io.novafoundation.nova.feature_assets.presentation.swap.network import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.common.utils.FragmentPayloadCreator +import io.novafoundation.nova.common.utils.FragmentPayloadHolder +import io.novafoundation.nova.common.utils.PayloadCreator import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment -class NetworkSwapFlowFragment : NetworkFlowFragment() { +class NetworkSwapFlowFragment : + NetworkFlowFragment(), + FragmentPayloadHolder { + + companion object : PayloadCreator by FragmentPayloadCreator() override fun inject() { FeatureUtils.getFeature(this, AssetsFeatureApi::class.java) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowPayload.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowPayload.kt new file mode 100644 index 0000000000..76d901f7d2 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowPayload.kt @@ -0,0 +1,12 @@ +package io.novafoundation.nova.feature_assets.presentation.swap.network + +import android.os.Parcelable +import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload +import io.novafoundation.nova.feature_assets.presentation.swap.asset.SwapFlowPayload +import kotlinx.android.parcel.Parcelize + +@Parcelize +class NetworkSwapFlowPayload( + val networkFlowPayload: NetworkFlowPayload, + val swapFlowPayload: SwapFlowPayload +) : Parcelable diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt index e76a369c76..bf4c149e93 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt @@ -13,10 +13,11 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.Control import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowViewModel import io.novafoundation.nova.feature_assets.presentation.flow.network.model.NetworkFlowRvItem -import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload -import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload +import io.novafoundation.nova.feature_assets.presentation.swap.executor.SwapFlowExecutor import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry +import io.novafoundation.nova.runtime.multiNetwork.asset import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.launch class NetworkSwapFlowViewModel( interactor: AssetNetworksInteractor, @@ -26,7 +27,8 @@ class NetworkSwapFlowViewModel( accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, networkFlowPayload: NetworkFlowPayload, - chainRegistry: ChainRegistry + chainRegistry: ChainRegistry, + private val swapFlowExecutor: SwapFlowExecutor ) : NetworkFlowViewModel( interactor, router, @@ -43,17 +45,17 @@ class NetworkSwapFlowViewModel( } override fun assetsFlow(tokenSymbol: TokenSymbol): Flow> { - return interactor.sendAssetFlow(tokenSymbol, externalBalancesFlow) + return interactor.swapAssetsFlow(tokenSymbol, externalBalancesFlow, coroutineScope) } override fun networkClicked(network: NetworkFlowRvItem) { - validate(network) { - val assetPayload = AssetPayload(network.chainId, network.assetId) - router.openSend(SendPayload.SpecifiedOrigin(assetPayload)) + launch { + val chainAsset = chainRegistry.asset(network.chainId, network.assetId) + swapFlowExecutor.openNextScreen(coroutineScope, chainAsset) } } override fun getTitle(tokenSymbol: TokenSymbol): String { - return resourceManager.getString(R.string.send_network_flow_title, tokenSymbol.value) + return resourceManager.getString(R.string.swap_network_flow_title, tokenSymbol.value) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowComponent.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowComponent.kt index 82df8c6688..afb00b0880 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowComponent.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowComponent.kt @@ -4,11 +4,8 @@ import androidx.fragment.app.Fragment import dagger.BindsInstance import dagger.Subcomponent import io.novafoundation.nova.common.di.scope.ScreenScope -import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowFragment -import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowFragment -import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload -import io.novafoundation.nova.feature_assets.presentation.send.flow.network.NetworkSendFlowFragment import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowFragment +import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowPayload @Subcomponent( modules = [ @@ -23,7 +20,7 @@ interface NetworkSwapFlowComponent { fun create( @BindsInstance fragment: Fragment, - @BindsInstance networkFlowPayload: NetworkFlowPayload + @BindsInstance payload: NetworkSwapFlowPayload ): NetworkSwapFlowComponent } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowModule.kt index 3e18ccbe93..23d8dc8c91 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/di/NetworkSwapFlowModule.kt @@ -14,11 +14,9 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.buy.flow.network.NetworkBuyFlowViewModel -import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload -import io.novafoundation.nova.feature_assets.presentation.send.flow.network.NetworkSendFlowViewModel +import io.novafoundation.nova.feature_assets.presentation.swap.executor.SwapFlowExecutorFactory +import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowPayload import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowViewModel -import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry @Module(includes = [ViewModelModule::class]) @@ -39,7 +37,8 @@ class NetworkSwapFlowModule { controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, - networkFlowPayload: NetworkFlowPayload, + executorFactory: SwapFlowExecutorFactory, + payload: NetworkSwapFlowPayload, chainRegistry: ChainRegistry ): ViewModel { return NetworkSwapFlowViewModel( @@ -49,8 +48,9 @@ class NetworkSwapFlowModule { controllableAssetCheck = controllableAssetCheck, accountUseCase = accountUseCase, resourceManager = resourceManager, - networkFlowPayload = networkFlowPayload, - chainRegistry = chainRegistry + networkFlowPayload = payload.networkFlowPayload, + chainRegistry = chainRegistry, + swapFlowExecutor = executorFactory.create(payload.swapFlowPayload) ) } } diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/SwapMainSettingsViewModel.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/SwapMainSettingsViewModel.kt index b490e7b23e..4cc3826b1a 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/SwapMainSettingsViewModel.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/SwapMainSettingsViewModel.kt @@ -330,6 +330,7 @@ class SwapMainSettingsViewModel( ?.token ?.configuration val payload = outAsset?.let { AssetPayload(it.chainId, it.id) } + swapRouter.selectAssetIn(payload) } } @@ -340,6 +341,7 @@ class SwapMainSettingsViewModel( ?.token ?.configuration val payload = inAsset?.let { AssetPayload(it.chainId, it.id) } + swapRouter.selectAssetOut(payload) } } From cdcd653d0cd70a7a9feaad9f033a78cea5203923 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 25 Oct 2024 10:20:57 +0200 Subject: [PATCH 21/78] Remove unused filter --- .../domain/networks/AssetNetworksInteractor.kt | 16 ++-------------- .../swap/network/NetworkSwapFlowViewModel.kt | 2 +- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt index f297c6a6e1..ce02ef17e3 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt @@ -15,7 +15,6 @@ import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletReposit import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance import io.novafoundation.nova.feature_wallet_api.domain.model.aggregatedBalanceByAsset -import io.novafoundation.nova.runtime.ext.fullId import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry import io.novafoundation.nova.runtime.multiNetwork.asset import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId @@ -64,20 +63,9 @@ class AssetNetworksInteractor( fun swapAssetsFlow( tokenSymbol: TokenSymbol, - externalBalancesFlow: Flow>, - coroutineScope: CoroutineScope + externalBalancesFlow: Flow> ): Flow> { - val filterFlow = getAvailableSwapAssets(tokenSymbol, coroutineScope).map { availableAssetsForSwap -> - val filter: AssetFilter = { asset -> - val chainAsset = asset.token.configuration - - chainAsset.fullId in availableAssetsForSwap - } - - filter - } - - return searchAssetsByTokenSymbolInternalFlow(tokenSymbol, externalBalancesFlow, filterFlow = filterFlow) + return searchAssetsByTokenSymbolInternalFlow(tokenSymbol, externalBalancesFlow, filter = null) } fun receiveAssetFlow( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt index bf4c149e93..93f84fd011 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt @@ -45,7 +45,7 @@ class NetworkSwapFlowViewModel( } override fun assetsFlow(tokenSymbol: TokenSymbol): Flow> { - return interactor.swapAssetsFlow(tokenSymbol, externalBalancesFlow, coroutineScope) + return interactor.swapAssetsFlow(tokenSymbol, externalBalancesFlow) } override fun networkClicked(network: NetworkFlowRvItem) { From b9e97ad24c621cfc6e61adc4fcdb82d5c110cbcf Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 25 Oct 2024 10:38:20 +0200 Subject: [PATCH 22/78] Fixed pr notes --- .../nova/caip/slip44/Slip44CoinRepository.kt | 4 +-- .../domain/common/AssetBalance.kt | 33 +++++++++++++++++++ .../domain/common/AssetPrefixNormalizing.kt | 26 --------------- .../domain/common/NetworkAssetSorting.kt | 10 +++--- .../domain/common/TokenAssetSorting.kt | 9 ++--- .../common/TotalAndTransferableBalance.kt | 33 ------------------- .../tokens/manage/ManageTokenInteractor.kt | 4 +-- .../balance/common/AssetListMixin.kt | 10 ++++-- .../common/mappers/AssetMappersCommon.kt | 4 +-- .../common/mappers/NetworkAssetMappers.kt | 8 ++--- .../common/mappers/TokenAssetMappers.kt | 12 +++---- .../balance/list/BalanceListViewModel.kt | 5 ++- .../send/flow/AssetSendFlowViewModel.kt | 4 +-- .../swap/AssetSwapFlowViewModel.kt | 4 +-- .../nova/runtime/ext/ChainExt.kt | 19 +++++++++-- 15 files changed, 89 insertions(+), 96 deletions(-) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetBalance.kt delete mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetPrefixNormalizing.kt delete mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TotalAndTransferableBalance.kt diff --git a/caip/src/main/java/io/novafoundation/nova/caip/slip44/Slip44CoinRepository.kt b/caip/src/main/java/io/novafoundation/nova/caip/slip44/Slip44CoinRepository.kt index ab89fb3db7..f53b2a864e 100644 --- a/caip/src/main/java/io/novafoundation/nova/caip/slip44/Slip44CoinRepository.kt +++ b/caip/src/main/java/io/novafoundation/nova/caip/slip44/Slip44CoinRepository.kt @@ -2,7 +2,7 @@ package io.novafoundation.nova.caip.slip44 import io.novafoundation.nova.caip.slip44.endpoint.Slip44CoinApi import io.novafoundation.nova.caip.slip44.endpoint.Slip44CoinRemote -import io.novafoundation.nova.runtime.ext.unifiedSymbol +import io.novafoundation.nova.runtime.ext.normalizeSymbol import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -26,7 +26,7 @@ internal class RealSlip44CoinRepository( .associateBy { it.symbol } } - return slip44Coins[chainAsset.unifiedSymbol()] + return slip44Coins[chainAsset.normalizeSymbol()] ?.index ?.toIntOrNull() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetBalance.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetBalance.kt new file mode 100644 index 0000000000..adb2947bdb --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetBalance.kt @@ -0,0 +1,33 @@ +package io.novafoundation.nova.feature_assets.domain.common + +import java.math.BigDecimal + +class AssetBalance( + val total: PricedAmount, + val transferable: PricedAmount +) { + + companion object { + val ZERO = AssetBalance(PricedAmount(BigDecimal.ZERO, BigDecimal.ZERO), PricedAmount(BigDecimal.ZERO, BigDecimal.ZERO)) + } + + operator fun plus(other: AssetBalance): AssetBalance { + return AssetBalance( + total + other.total, + transferable + other.transferable + ) + } +} + +class PricedAmount( + val amount: BigDecimal, + val fiat: BigDecimal +) { + + operator fun plus(other: PricedAmount): PricedAmount { + return PricedAmount( + amount + other.amount, + fiat + other.fiat + ) + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetPrefixNormalizing.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetPrefixNormalizing.kt deleted file mode 100644 index bd231e38c4..0000000000 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/AssetPrefixNormalizing.kt +++ /dev/null @@ -1,26 +0,0 @@ -package io.novafoundation.nova.feature_assets.domain.common - -import io.novafoundation.nova.common.utils.TokenSymbol -import io.novafoundation.nova.common.utils.asTokenSymbol - -/** - * Some of tokens may have a prefix but may still be original token (like xcDOT, xcHDX) - * For some cases we need to normalize token symbol to original format - */ - -private val normalizingPrefixList: List - get() = listOf("xc") - -fun normalizeTokenSymbol(tokenSymbol: TokenSymbol): TokenSymbol { - return normalizeTokenSymbol(tokenSymbol.value).asTokenSymbol() -} - -fun normalizeTokenSymbol(symbol: String): String { - normalizingPrefixList.forEach { prefix -> - if (symbol.startsWith(prefix)) { - return symbol.removePrefix(prefix) - } - } - - return symbol -} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/NetworkAssetSorting.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/NetworkAssetSorting.kt index 8edfb2b18c..e4b816da01 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/NetworkAssetSorting.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/NetworkAssetSorting.kt @@ -21,7 +21,7 @@ class NetworkAssetGroup( class AssetWithOffChainBalance( val asset: Asset, - val balanceWithOffchain: TotalAndTransferableBalance, + val balanceWithOffchain: AssetBalance, ) fun groupAndSortAssetsByNetwork( @@ -63,7 +63,7 @@ fun getAssetGroupBaseComparator( .then(Chain.defaultComparatorFrom(NetworkAssetGroup::chain)) } -fun Asset.totalWithOffChain(externalBalances: Map): TotalAndTransferableBalance { +fun Asset.totalWithOffChain(externalBalances: Map): AssetBalance { val onChainTotal = total val offChainTotal = externalBalances[token.configuration.fullId] ?.let(token::amountFromPlanks) @@ -72,8 +72,8 @@ fun Asset.totalWithOffChain(externalBalances: Map): T val overallTotal = onChainTotal + offChainTotal val overallFiat = token.amountToFiat(overallTotal) - return TotalAndTransferableBalance( - Amount(overallTotal, overallFiat), - Amount(transferable, token.amountToFiat(transferable)) + return AssetBalance( + PricedAmount(overallTotal, overallFiat), + PricedAmount(transferable, token.amountToFiat(transferable)) ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt index d9457f21de..70328ddfaf 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt @@ -7,13 +7,14 @@ import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.CoinRateChange import io.novafoundation.nova.runtime.ext.defaultComparatorFrom import io.novafoundation.nova.runtime.ext.isUtilityAsset +import io.novafoundation.nova.runtime.ext.normalize import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId import java.math.BigDecimal class TokenAssetGroup( val token: Token, - val groupBalance: TotalAndTransferableBalance + val groupBalance: AssetBalance ) { data class Token( @@ -27,7 +28,7 @@ class TokenAssetGroup( class AssetWithNetwork( val chain: Chain, val asset: Asset, - val balanceWithOffChain: TotalAndTransferableBalance, + val balanceWithOffChain: AssetBalance, ) fun groupAndSortAssetsByToken( @@ -45,7 +46,7 @@ fun groupAndSortAssetsByToken( .mapKeys { (token, assets) -> TokenAssetGroup( token = token, - groupBalance = assets.fold(TotalAndTransferableBalance.ZERO) { acc, element -> acc + element.balanceWithOffChain }, + groupBalance = assets.fold(AssetBalance.ZERO) { acc, element -> acc + element.balanceWithOffChain }, ) }.toSortedMap(assetGroupComparator) } @@ -68,7 +69,7 @@ fun getTokenAssetGroupBaseComparator( private fun mapToTokenGroup(it: AssetWithNetwork) = TokenAssetGroup.Token( it.asset.token.configuration.iconUrl, - normalizeTokenSymbol(it.asset.token.configuration.symbol), + it.asset.token.configuration.symbol.normalize(), it.asset.token.currency, it.asset.token.coinRate ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TotalAndTransferableBalance.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TotalAndTransferableBalance.kt deleted file mode 100644 index 4d5b21e3e9..0000000000 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TotalAndTransferableBalance.kt +++ /dev/null @@ -1,33 +0,0 @@ -package io.novafoundation.nova.feature_assets.domain.common - -import java.math.BigDecimal - -class TotalAndTransferableBalance( - val total: Amount, - val transferable: Amount -) { - - companion object { - val ZERO = TotalAndTransferableBalance(Amount(BigDecimal.ZERO, BigDecimal.ZERO), Amount(BigDecimal.ZERO, BigDecimal.ZERO)) - } - - operator fun plus(other: TotalAndTransferableBalance): TotalAndTransferableBalance { - return TotalAndTransferableBalance( - total + other.total, - transferable + other.transferable - ) - } -} - -class Amount( - val amount: BigDecimal, - val fiat: BigDecimal -) { - - operator fun plus(other: Amount): Amount { - return Amount( - amount + other.amount, - fiat + other.fiat - ) - } -} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/manage/ManageTokenInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/manage/ManageTokenInteractor.kt index bb838e4e15..ebd60d114b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/manage/ManageTokenInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/manage/ManageTokenInteractor.kt @@ -6,7 +6,7 @@ import io.novafoundation.nova.feature_assets.domain.tokens.AssetsDataCleaner import io.novafoundation.nova.feature_wallet_api.domain.interfaces.ChainAssetRepository import io.novafoundation.nova.runtime.ext.defaultComparator import io.novafoundation.nova.runtime.ext.fullId -import io.novafoundation.nova.runtime.ext.unifiedSymbol +import io.novafoundation.nova.runtime.ext.normalizeSymbol import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry import io.novafoundation.nova.runtime.multiNetwork.ChainWithAsset import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain @@ -92,7 +92,7 @@ class RealManageTokenInteractor( val enabledAssets = assetsWithChains.filter { it.asset.enabled } .map { it.asset.fullId } - return assetsWithChains.groupBy { (_, asset) -> asset.unifiedSymbol() } + return assetsWithChains.groupBy { (_, asset) -> asset.normalizeSymbol() } .map { (symbol, chainsWithAssets) -> val (_, firstAsset) = chainsWithAssets.first() val tokenAssets = chainsWithAssets.filter { it.asset.enabled } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index bf235f7a33..ca95a9b204 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -15,9 +15,11 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.ite import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_wallet_api.domain.model.Asset +import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first @@ -40,6 +42,10 @@ class AssetListMixinFactory( interface AssetListMixin { + val assetsViewModeFlow: Flow + + val externalBalancesFlow: SharedFlow> + val assetsFlow: Flow> val filteredAssetsFlow: Flow> @@ -47,8 +53,8 @@ interface AssetListMixin { val assetModelsFlow: Flow> fun expandToken(tokenGroupUi: TokenGroupUi) + suspend fun switchViewMode() - val assetsViewModeFlow: Flow } class RealAssetListMixin( @@ -68,7 +74,7 @@ class RealAssetListMixin( private val selectedCurrency = currencyInteractor.observeSelectCurrency() .shareInBackground() - private val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() + override val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() .shareInBackground() private val expandedTokenIdsFlow = MutableStateFlow(setOf()) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt index 524a814cdc..a0230ef97c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt @@ -6,7 +6,7 @@ import io.novafoundation.nova.common.utils.isNonNegative import io.novafoundation.nova.common.utils.isZero import io.novafoundation.nova.common.utils.orZero import io.novafoundation.nova.feature_assets.R -import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.model.TokenModel import io.novafoundation.nova.feature_currency_api.domain.model.Currency @@ -24,7 +24,7 @@ fun mapCoinRateChange(coinRateChange: CoinRateChange?, currency: Currency): Stri fun mapAssetToAssetModel( asset: Asset, - balance: Amount + balance: PricedAmount ): AssetModel { return AssetModel( token = mapTokenToTokenModel(asset.token), diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt index c352bb6d15..2b5197665f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt @@ -3,10 +3,10 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mapper import io.novafoundation.nova.common.list.GroupedList import io.novafoundation.nova.common.list.toListWithHeaders import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi -import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance -import io.novafoundation.nova.feature_assets.domain.common.TotalAndTransferableBalance +import io.novafoundation.nova.feature_assets.domain.common.AssetBalance import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkAssetUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkGroupUi @@ -17,7 +17,7 @@ import java.math.BigDecimal fun GroupedList.mapGroupedAssetsToUi( currency: Currency, groupBalance: (NetworkAssetGroup) -> BigDecimal = NetworkAssetGroup::groupTotalBalanceFiat, - balance: (TotalAndTransferableBalance) -> Amount = TotalAndTransferableBalance::total, + balance: (AssetBalance) -> PricedAmount = AssetBalance::total, ): List { return mapKeys { (assetGroup, _) -> mapAssetGroupToUi(assetGroup, currency, groupBalance) } .mapValues { (_, assets) -> mapAssetsToAssetModels(assets, balance) } @@ -27,7 +27,7 @@ fun GroupedList.mapGroupedAssetsToU private fun mapAssetsToAssetModels( assets: List, - balance: (TotalAndTransferableBalance) -> Amount + balance: (AssetBalance) -> PricedAmount ): List { return assets.map { NetworkAssetUi(mapAssetToAssetModel(it.asset, balance(it.balanceWithOffchain))) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index 54d853825f..1f9bffdea5 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -6,10 +6,10 @@ import io.novafoundation.nova.common.utils.formatTokenAmount import io.novafoundation.nova.common.utils.formatting.formatAsChange import io.novafoundation.nova.common.utils.orZero import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi -import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup -import io.novafoundation.nova.feature_assets.domain.common.TotalAndTransferableBalance +import io.novafoundation.nova.feature_assets.domain.common.AssetBalance import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi @@ -17,8 +17,8 @@ import io.novafoundation.nova.feature_currency_api.presentation.formatters.forma import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel fun GroupedList.mapGroupedAssetsToUi( - groupBalance: (TokenAssetGroup) -> Amount = { it.groupBalance.total }, - balance: (TotalAndTransferableBalance) -> Amount = TotalAndTransferableBalance::total, + groupBalance: (TokenAssetGroup) -> PricedAmount = { it.groupBalance.total }, + balance: (AssetBalance) -> PricedAmount = AssetBalance::total, ): List { return mapKeys { (assetGroup, _) -> mapAssetGroupToUi(assetGroup, groupBalance) } .mapValues { (_, assets) -> mapAssetsToAssetModels(assets, balance) } @@ -28,14 +28,14 @@ fun GroupedList.mapGroupedAssetsToUi( private fun mapAssetsToAssetModels( assets: List, - balance: (TotalAndTransferableBalance) -> Amount + balance: (AssetBalance) -> PricedAmount ): List { return assets.map { TokenAssetUi(mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } } private fun mapAssetGroupToUi( assetGroup: TokenAssetGroup, - groupBalance: (TokenAssetGroup) -> Amount + groupBalance: (TokenAssetGroup) -> PricedAmount ): BalanceListRvItem { val balance = groupBalance(assetGroup) return TokenGroupUi( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt index 8407170880..5a0f9a6d89 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt @@ -90,11 +90,10 @@ class BalanceListViewModel( { walletInteractor.syncAssetsRates(selectedCurrency.first()) }, walletInteractor::syncAllNfts ) - - private val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() - val assetListMixin = assetListMixinFactory.create(viewModelScope) + private val externalBalancesFlow = assetListMixin.externalBalancesFlow + private val isFiltersEnabledFlow = walletInteractor.isFiltersEnabledFlow() private val accountChangeSyncActions: List = listOf( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt index 1576b47bb6..15ecd25dc0 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/AssetSendFlowViewModel.kt @@ -8,7 +8,7 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance -import io.novafoundation.nova.feature_assets.domain.common.TotalAndTransferableBalance +import io.novafoundation.nova.feature_assets.domain.common.AssetBalance import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi @@ -50,7 +50,7 @@ class AssetSendFlowViewModel( } override fun mapAssets(assets: Map>, currency: Currency): List { - return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, TotalAndTransferableBalance::transferable) + return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, AssetBalance::transferable) } override fun getPlaceholder(query: String, assets: List): PlaceholderModel? { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt index ad84bc9623..02e7afb10d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/AssetSwapFlowViewModel.kt @@ -9,7 +9,7 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance -import io.novafoundation.nova.feature_assets.domain.common.TotalAndTransferableBalance +import io.novafoundation.nova.feature_assets.domain.common.AssetBalance import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi @@ -76,6 +76,6 @@ class AssetSwapFlowViewModel( } override fun mapAssets(assets: Map>, currency: Currency): List { - return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, TotalAndTransferableBalance::transferable) + return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, AssetBalance::transferable) } } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/ext/ChainExt.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/ext/ChainExt.kt index 8d084be570..f796f0351e 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/ext/ChainExt.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/ext/ChainExt.kt @@ -3,7 +3,9 @@ package io.novafoundation.nova.runtime.ext import io.novafoundation.nova.common.data.network.runtime.binding.MultiAddress import io.novafoundation.nova.common.data.network.runtime.binding.bindOrNull import io.novafoundation.nova.common.utils.Modules +import io.novafoundation.nova.common.utils.TokenSymbol import io.novafoundation.nova.common.utils.Urls +import io.novafoundation.nova.common.utils.asTokenSymbol import io.novafoundation.nova.common.utils.emptyEthereumAccountId import io.novafoundation.nova.common.utils.emptySubstrateAccountId import io.novafoundation.nova.common.utils.findIsInstanceOrNull @@ -196,10 +198,21 @@ val Chain.Asset.isUtilityAsset: Boolean inline val Chain.Asset.isCommissionAsset: Boolean get() = isUtilityAsset -private const val MOONBEAM_XC_PREFIX = "xc" +private const val XC_PREFIX = "xc" -fun Chain.Asset.unifiedSymbol(): String { - return symbol.value.removePrefix(MOONBEAM_XC_PREFIX) +fun Chain.Asset.normalizeSymbol(): String { + return normalizeTokenSymbol(this.symbol.value) +} + +fun TokenSymbol.normalize(): TokenSymbol { + return normalizeTokenSymbol(value).asTokenSymbol() +} + +fun normalizeTokenSymbol(symbol: String): String { + if (symbol.startsWith(XC_PREFIX)) { + return symbol.removePrefix(XC_PREFIX) + } + return symbol } val Chain.Node.isWss: Boolean From a425c2fab839f1cb97f5b23c2db3e71d24b05cb7 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 25 Oct 2024 17:12:21 +0200 Subject: [PATCH 23/78] Add colored asset icon support --- .../nova/ChainMappingIntegrationTest.kt | 7 ++- .../nova/common/data/model/AssetIconMode.kt | 5 ++ .../data/repository/AssetsIconModeService.kt | 54 +++++++++++++++++++ ...Repository.kt => AssetsViewModeService.kt} | 6 +-- .../nova/common/di/CommonApi.kt | 7 ++- .../nova/common/di/modules/CommonModule.kt | 12 +++-- .../res/drawable/ic_token_dot_colored.xml | 27 ++++++++++ .../src/main/res/layout/view_labeled_text.xml | 4 +- .../di/AssetsFeatureDependencies.kt | 4 +- .../feature_assets/di/AssetsFeatureModule.kt | 6 +-- .../assets/list/AssetsListInteractor.kt | 8 +-- .../assets/search/AssetSearchInteractor.kt | 12 ++--- .../domain/tokens/add/AddTokensInteractor.kt | 2 +- .../balance/list/di/BalanceListModule.kt | 6 +-- .../tokens/manage/ManageTokensAdapter.kt | 4 +- .../res/layout/fragment_balance_detail.xml | 5 +- .../layout/item_manage_token_multichain.xml | 2 +- .../main/res/layout/item_network_asset.xml | 6 +-- .../src/main/res/layout/item_token_asset.xml | 6 +-- .../res/layout/item_token_asset_group.xml | 6 +-- feature-assets/src/main/res/values/styles.xml | 1 - .../domain/sign/evm/EvmSignInteractor.kt | 2 +- .../domain/utils/CustomChainFactory.kt | 2 +- .../presentation/view/SwapAssetView.kt | 2 - .../src/main/res/layout/view_swap_asset.xml | 4 +- .../presentation/views/SwapAmountInputView.kt | 3 -- .../res/layout/view_swap_amount_input.xml | 6 +-- .../main/res/layout/item_asset_selector.xml | 1 - .../main/res/layout/view_asset_selector.xml | 4 +- .../res/layout/view_choose_amount_input.xml | 2 - .../repository/RealChainAssetRepository.kt | 3 +- runtime/build.gradle | 16 +++--- .../nova/runtime/di/ChainRegistryModule.kt | 7 ++- .../nova/runtime/di/RuntimeDependencies.kt | 3 ++ .../nova/runtime/di/RuntimeModule.kt | 11 +++- .../runtime/multiNetwork/ChainRegistry.kt | 11 ++-- .../chain/mappers/DomainToLocalChainMapper.kt | 2 +- .../chain/mappers/LocalToDomainChainMapper.kt | 27 +++++++--- .../RemoteToDomainChainMapperFacade.kt | 7 ++- .../runtime/multiNetwork/chain/model/Chain.kt | 16 +++++- 40 files changed, 224 insertions(+), 95 deletions(-) create mode 100644 common/src/main/java/io/novafoundation/nova/common/data/model/AssetIconMode.kt create mode 100644 common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsIconModeService.kt rename common/src/main/java/io/novafoundation/nova/common/data/repository/{AssetsViewModeRepository.kt => AssetsViewModeService.kt} (93%) create mode 100644 common/src/main/res/drawable/ic_token_dot_colored.xml diff --git a/app/src/androidTest/java/io/novafoundation/nova/ChainMappingIntegrationTest.kt b/app/src/androidTest/java/io/novafoundation/nova/ChainMappingIntegrationTest.kt index bb0a481b88..3ae472fde7 100644 --- a/app/src/androidTest/java/io/novafoundation/nova/ChainMappingIntegrationTest.kt +++ b/app/src/androidTest/java/io/novafoundation/nova/ChainMappingIntegrationTest.kt @@ -4,6 +4,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.gson.Gson import androidx.test.platform.app.InstrumentationRegistry import dagger.Component +import io.novafoundation.nova.common.data.model.AssetIconMode import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.di.CommonApi import io.novafoundation.nova.common.di.FeatureContainer @@ -100,7 +101,8 @@ class ChainMappingIntegrationTest { assetsLocal = assetsLocal, explorersLocal = explorersLocal, externalApisLocal = externalApisLocal, - gson = gson + gson = gson, + assetIconMode = AssetIconMode.COLORED ) } @@ -123,7 +125,8 @@ class ChainMappingIntegrationTest { assetsLocal = assetsLocal, explorersLocal = explorersLocal, externalApisLocal = externalApisLocal, - gson = gson + gson = gson, + assetIconMode = AssetIconMode.COLORED ) } } diff --git a/common/src/main/java/io/novafoundation/nova/common/data/model/AssetIconMode.kt b/common/src/main/java/io/novafoundation/nova/common/data/model/AssetIconMode.kt new file mode 100644 index 0000000000..76fda50d5f --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/data/model/AssetIconMode.kt @@ -0,0 +1,5 @@ +package io.novafoundation.nova.common.data.model + +enum class AssetIconMode { + COLORED, WHITE +} diff --git a/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsIconModeService.kt b/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsIconModeService.kt new file mode 100644 index 0000000000..7d75ee2560 --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsIconModeService.kt @@ -0,0 +1,54 @@ +package io.novafoundation.nova.common.data.repository + +import io.novafoundation.nova.common.data.model.AssetIconMode +import io.novafoundation.nova.common.data.storage.Preferences +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext + +interface AssetsIconModeService { + fun assetsIconModeFlow(): Flow + + suspend fun setAssetsIconMode(assetsViewMode: AssetIconMode) + + fun getIconMode(): AssetIconMode +} + +private const val PREFS_ASSETS_ICON_MODE = "PREFS_ASSETS_ICON_MODE" +private val ASSET_ICON_MODE_DEFAULT = AssetIconMode.COLORED + +class RealAssetsIconModeService( + private val preferences: Preferences +) : AssetsIconModeService { + + override fun assetsIconModeFlow(): Flow { + return preferences.stringFlow(PREFS_ASSETS_ICON_MODE) + .map { + it?.fromPrefsValue() ?: ASSET_ICON_MODE_DEFAULT + } + } + + override suspend fun setAssetsIconMode(assetsViewMode: AssetIconMode) = withContext(Dispatchers.IO) { + preferences.putString(PREFS_ASSETS_ICON_MODE, assetsViewMode.toPrefsValue()) + } + + override fun getIconMode(): AssetIconMode { + return preferences.getString(PREFS_ASSETS_ICON_MODE)?.fromPrefsValue() ?: ASSET_ICON_MODE_DEFAULT + } + + private fun AssetIconMode.toPrefsValue(): String { + return when (this) { + AssetIconMode.COLORED -> "colored" + AssetIconMode.WHITE -> "solid" + } + } + + private fun String.fromPrefsValue(): AssetIconMode? { + return when (this) { + "colored" -> AssetIconMode.COLORED + "solid" -> AssetIconMode.WHITE + else -> null + } + } +} diff --git a/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt b/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeService.kt similarity index 93% rename from common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt rename to common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeService.kt index d1438523eb..cf3d27cfbd 100644 --- a/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt +++ b/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeService.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext -interface AssetsViewModeRepository { +interface AssetsViewModeService { fun assetsViewModeFlow(): Flow suspend fun setAssetsViewMode(assetsViewMode: AssetViewMode) } @@ -15,9 +15,9 @@ interface AssetsViewModeRepository { private const val PREFS_ASSETS_VIEW_MODE = "PREFS_ASSETS_VIEW_MODE" private val ASSET_VIEW_MODE_DEFAULT = AssetViewMode.TOKENS -class RealAssetsViewModeRepository( +class RealAssetsViewModeService( private val preferences: Preferences -) : AssetsViewModeRepository { +) : AssetsViewModeService { override fun assetsViewModeFlow(): Flow { return preferences.stringFlow(PREFS_ASSETS_VIEW_MODE) diff --git a/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt b/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt index 0da563e315..02bafdac71 100644 --- a/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt +++ b/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt @@ -14,7 +14,8 @@ import io.novafoundation.nova.common.data.network.HttpExceptionHandler import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser import io.novafoundation.nova.common.data.network.rpc.SocketSingleRequestExecutor -import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository +import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsViewModeService import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1 import io.novafoundation.nova.common.data.secrets.v2.SecretStoreV2 @@ -155,7 +156,9 @@ interface CommonApi { fun buildTypeProvider(): BuildTypeProvider - fun assetsViewModeRepository(): AssetsViewModeRepository + fun assetsViewModeRepository(): AssetsViewModeService + + fun assetsIconModeService(): AssetsIconModeService val systemCallExecutor: SystemCallExecutor diff --git a/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt b/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt index 3715d0f894..c74a772484 100644 --- a/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt +++ b/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt @@ -19,9 +19,11 @@ import io.novafoundation.nova.common.data.RealGoogleApiAvailabilityProvider import io.novafoundation.nova.common.data.memory.ComputationalCache import io.novafoundation.nova.common.data.memory.RealComputationalCache import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser -import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository +import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsViewModeService import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository -import io.novafoundation.nova.common.data.repository.RealAssetsViewModeRepository +import io.novafoundation.nova.common.data.repository.RealAssetsIconModeService +import io.novafoundation.nova.common.data.repository.RealAssetsViewModeService import io.novafoundation.nova.common.data.repository.RealBannerVisibilityRepository import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1 import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1Impl @@ -352,5 +354,9 @@ class CommonModule { @Provides @ApplicationScope - fun assetsViewModeRepository(preferences: Preferences): AssetsViewModeRepository = RealAssetsViewModeRepository(preferences) + fun assetsViewModeService(preferences: Preferences): AssetsViewModeService = RealAssetsViewModeService(preferences) + + @Provides + @ApplicationScope + fun assetsIconModeService(preferences: Preferences): AssetsIconModeService = RealAssetsIconModeService(preferences) } diff --git a/common/src/main/res/drawable/ic_token_dot_colored.xml b/common/src/main/res/drawable/ic_token_dot_colored.xml new file mode 100644 index 0000000000..6bf4dc417f --- /dev/null +++ b/common/src/main/res/drawable/ic_token_dot_colored.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/common/src/main/res/layout/view_labeled_text.xml b/common/src/main/res/layout/view_labeled_text.xml index 79b30095ba..812438890f 100644 --- a/common/src/main/res/layout/view_labeled_text.xml +++ b/common/src/main/res/layout/view_labeled_text.xml @@ -16,7 +16,9 @@ android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + tools:src="@drawable/ic_token_dot_colored" + tools:visibility="visible" /> { val filter = { asset: Asset -> asset.token.configuration.buyProviders.isNotEmpty() } - return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> + return assetsViewModeService.assetsViewModeFlow().flatMapLatest { viewMode -> when (viewMode) { AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = filter) .map { AssetFlowSearchResult.ByNetworks(it) } @@ -68,7 +68,7 @@ class AssetSearchInteractor( ): Flow { val filter = { asset: Asset -> asset.transferableInPlanks.isPositive() } - return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> + return assetsViewModeService.assetsViewModeFlow().flatMapLatest { viewMode -> when (viewMode) { AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow( queryFlow, @@ -106,7 +106,7 @@ class AssetSearchInteractor( filter } - return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> + return assetsViewModeService.assetsViewModeFlow().flatMapLatest { viewMode -> when (viewMode) { AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filterFlow = filterFlow) .map { AssetFlowSearchResult.ByNetworks(it) } @@ -121,7 +121,7 @@ class AssetSearchInteractor( queryFlow: Flow, externalBalancesFlow: Flow>, ): Flow { - return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> + return assetsViewModeService.assetsViewModeFlow().flatMapLatest { viewMode -> when (viewMode) { AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = null) .map { AssetFlowSearchResult.ByNetworks(it) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/add/AddTokensInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/add/AddTokensInteractor.kt index 06b9c5f640..170b42b074 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/add/AddTokensInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/add/AddTokensInteractor.kt @@ -77,7 +77,7 @@ class RealAddTokensInteractor( val priceId = coinGeckoLinkParser.parse(customErc20Token.priceLink).getOrNull()?.priceId val asset = Chain.Asset( - iconUrl = null, + icon = null, id = chainAssetIdOfErc20Token(customErc20Token.contract), priceId = priceId, chainId = customErc20Token.chainId, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt index dfdcbc7bc4..bd955e79e0 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt @@ -6,7 +6,7 @@ import androidx.lifecycle.ViewModelProvider import dagger.Module import dagger.Provides import dagger.multibindings.IntoMap -import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository +import io.novafoundation.nova.common.data.repository.AssetsViewModeService import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey @@ -37,8 +37,8 @@ class BalanceListModule { accountRepository: AccountRepository, nftRepository: NftRepository, bannerVisibilityRepository: BannerVisibilityRepository, - assetsViewModeRepository: AssetsViewModeRepository - ) = AssetsListInteractor(accountRepository, nftRepository, bannerVisibilityRepository, assetsViewModeRepository) + assetsViewModeService: AssetsViewModeService + ) = AssetsListInteractor(accountRepository, nftRepository, bannerVisibilityRepository, assetsViewModeService) @Provides @ScreenScope diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt index c03b01efd9..ff3b442deb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt @@ -10,7 +10,6 @@ import io.novafoundation.nova.common.list.BaseViewHolder import io.novafoundation.nova.common.list.PayloadGenerator import io.novafoundation.nova.common.list.resolvePayload import io.novafoundation.nova.common.utils.inflateChild -import io.novafoundation.nova.common.utils.setImageTintRes import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.R @@ -91,8 +90,9 @@ class ManageTokensViewHolder( itemManageTokenMultichainEnabled.isChecked = item.enabled itemManageTokenMultichainEnabled.isEnabled = item.switchable + itemManageTokenMultichainIcon.alpha = if (item.enabled) 1f else 0.48f + val contentColorRes = if (item.enabled) R.color.text_primary else R.color.text_secondary - itemManageTokenMultichainIcon.setImageTintRes(contentColorRes) itemManageTokenMultichainSymbol.setTextColorRes(contentColorRes) } diff --git a/feature-assets/src/main/res/layout/fragment_balance_detail.xml b/feature-assets/src/main/res/layout/fragment_balance_detail.xml index 83c3fd3dc5..420e7a9470 100644 --- a/feature-assets/src/main/res/layout/fragment_balance_detail.xml +++ b/feature-assets/src/main/res/layout/fragment_balance_detail.xml @@ -53,8 +53,7 @@ app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="@+id/balanceDetailTokenName" - app:tint="@color/icon_primary" /> + app:layout_constraintTop_toTopOf="@+id/balanceDetailTokenName" /> + tools:text="$10.25" /> + tools:src="@drawable/ic_token_dot_colored" /> + tools:src="@drawable/ic_token_dot_colored" /> + tools:text="DOT" /> + tools:src="@drawable/ic_token_dot_colored" /> + tools:text="DOT" /> + tools:src="@drawable/ic_token_dot_colored" /> + tools:text="DOT" /> diff --git a/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/evm/EvmSignInteractor.kt b/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/evm/EvmSignInteractor.kt index fd8cea9162..9d45570312 100644 --- a/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/evm/EvmSignInteractor.kt +++ b/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/evm/EvmSignInteractor.kt @@ -311,7 +311,7 @@ class EvmSignInteractor( val chainCurrency = evmChain.nativeCurrency return Chain.Asset( - iconUrl = evmChain.iconUrl, + icon = evmChain.iconUrl?.let { Chain.Icon(it) }, id = 0, priceId = null, chainId = evmChain.chainId, diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/domain/utils/CustomChainFactory.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/domain/utils/CustomChainFactory.kt index 2a6ec8f606..f63fb16290 100644 --- a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/domain/utils/CustomChainFactory.kt +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/domain/utils/CustomChainFactory.kt @@ -91,7 +91,7 @@ class CustomChainFactory( id = 0, name = payload.chainName, enabled = true, - iconUrl = prefilledUtilityAsset?.iconUrl, + icon = prefilledUtilityAsset?.icon, priceId = priceId, chainId = chainId, symbol = payload.tokenSymbol.asTokenSymbol(), diff --git a/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt b/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt index adfe97ee92..dfd7591b82 100644 --- a/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt +++ b/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt @@ -9,7 +9,6 @@ import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.WithContextExtensions import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.common.utils.images.setIcon -import io.novafoundation.nova.common.utils.setImageTint import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.common.utils.setTextOrHide import io.novafoundation.nova.common.view.shape.getInputBackground @@ -49,7 +48,6 @@ class SwapAssetView @JvmOverloads constructor( } private fun setAssetImageUrl(icon: Icon) { - swapAssetImage.setImageTint(context.getColor(R.color.icon_primary)) swapAssetImage.setIcon(icon, imageLoader) swapAssetImage.setBackgroundResource(R.drawable.bg_token_container) } diff --git a/feature-swap-api/src/main/res/layout/view_swap_asset.xml b/feature-swap-api/src/main/res/layout/view_swap_asset.xml index ab2bbf7b30..854c4cf9ef 100644 --- a/feature-swap-api/src/main/res/layout/view_swap_asset.xml +++ b/feature-swap-api/src/main/res/layout/view_swap_asset.xml @@ -13,12 +13,10 @@ android:layout_height="40dp" android:layout_marginTop="16dp" android:background="@drawable/bg_token_container" - android:padding="5dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:tint="@color/icon_primary" - tools:src="@drawable/ic_token_ksm" /> + tools:src="@drawable/ic_token_dot_colored" /> { - swapAmountInputImage.setImageTint(context.getColor(R.color.icon_primary)) swapAmountInputImage.loadTokenIcon(icon.assetIconUrl, imageLoader) swapAmountInputImage.setBackgroundResource(R.drawable.bg_token_container) } SwapInputAssetModel.SwapAssetIcon.NotChosen -> { - swapAmountInputImage.setImageTint(context.getColor(R.color.icon_accent)) swapAmountInputImage.setImageResource(R.drawable.ic_add) swapAmountInputImage.setBackgroundResource(R.drawable.ic_swap_asset_default_background) } diff --git a/feature-swap-impl/src/main/res/layout/view_swap_amount_input.xml b/feature-swap-impl/src/main/res/layout/view_swap_amount_input.xml index 0f70968c2c..c89b1fa759 100644 --- a/feature-swap-impl/src/main/res/layout/view_swap_amount_input.xml +++ b/feature-swap-impl/src/main/res/layout/view_swap_amount_input.xml @@ -20,12 +20,10 @@ android:layout_marginTop="16dp" android:layout_marginBottom="16dp" android:background="@drawable/bg_token_container" - android:padding="5dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:tint="@color/icon_primary" - tools:src="@drawable/ic_token_ksm" /> + tools:src="@drawable/ic_token_dot_colored" /> diff --git a/feature-wallet-api/src/main/res/layout/item_asset_selector.xml b/feature-wallet-api/src/main/res/layout/item_asset_selector.xml index 55d9d464a9..aae6877e27 100644 --- a/feature-wallet-api/src/main/res/layout/item_asset_selector.xml +++ b/feature-wallet-api/src/main/res/layout/item_asset_selector.xml @@ -28,7 +28,6 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toEndOf="@+id/itemAssetSelectorCheckmark" app:layout_constraintTop_toTopOf="parent" - app:tint="@color/icon_primary" tools:src="@drawable/ic_token_dot" /> + tools:src="@drawable/ic_token_dot_colored" /> { - return chainAssetDao.getEnabledAssets().map { mapChainAssetLocalToAsset(it, gson) } + return chainAssetDao.getEnabledAssets().map { mapChainAssetLocalToAsset(it, gson, AssetIconMode.WHITE) } } } diff --git a/runtime/build.gradle b/runtime/build.gradle index 9a5db02627..1e96af753e 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -7,22 +7,24 @@ apply plugin: 'kotlin-android-extensions' android { compileSdkVersion rootProject.compileSdkVersion - defaultConfig { minSdkVersion rootProject.minSdkVersion targetSdkVersion rootProject.targetSdkVersion testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v20/chains_dev.json\"" + buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/chains_dev.json\"" buildConfigField "String", "EVM_ASSETS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/assets/evm/v2/assets_dev.json\"" - buildConfigField "String", "PRE_CONFIGURED_CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v20/preConfigured/chains_dev.json\"" - buildConfigField "String", "PRE_CONFIGURED_CHAIN_DETAILS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v20/preConfigured/detailsDev\"" + buildConfigField "String", "PRE_CONFIGURED_CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/preConfigured/chains_dev.json\"" + buildConfigField "String", "PRE_CONFIGURED_CHAIN_DETAILS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/preConfigured/detailsDev\"" buildConfigField "String", "TEST_CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/tests/chains_for_testBalance.json\"" buildConfigField "String", "INFURA_API_KEY", readStringSecret("INFURA_API_KEY") buildConfigField "String", "DWELLIR_API_KEY", readStringSecret("DWELLIR_API_KEY") + + buildConfigField "String", "ASSET_COLORED_ICON_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/icons/tokens/colored/\"" + buildConfigField "String", "ASSET_WHITE_ICON_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/icons/tokens/white/\"" } buildTypes { @@ -34,10 +36,10 @@ android { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v20/chains.json\"" + buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/chains.json\"" buildConfigField "String", "EVM_ASSETS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/assets/evm/v2/assets.json\"" - buildConfigField "String", "PRE_CONFIGURED_CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v20/preConfigured/chains.json\"" - buildConfigField "String", "PRE_CONFIGURED_CHAIN_DETAILS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v20/preConfigured/details\"" + buildConfigField "String", "PRE_CONFIGURED_CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/preConfigured/chains.json\"" + buildConfigField "String", "PRE_CONFIGURED_CHAIN_DETAILS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/preConfigured/details\"" } } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt index 97e74a266d..965c36544b 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt @@ -6,6 +6,7 @@ import dagger.Provides import io.novafoundation.nova.common.BuildConfig import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.network.rpc.BulkRetriever +import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.ApplicationScope import io.novafoundation.nova.common.interfaces.FileProvider @@ -228,7 +229,8 @@ class ChainRegistryModule { baseTypeSynchronizer: BaseTypeSynchronizer, runtimeSyncService: RuntimeSyncService, web3ApiPool: Web3ApiPool, - gson: Gson + gson: Gson, + assetsIconModeService: AssetsIconModeService ) = ChainRegistry( runtimeProviderPool, chainConnectionPool, @@ -239,6 +241,7 @@ class ChainRegistryModule { baseTypeSynchronizer, runtimeSyncService, web3ApiPool, - gson + gson, + assetsIconModeService ) } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeDependencies.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeDependencies.kt index 4b6975a99b..c681bac045 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeDependencies.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeDependencies.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.runtime.di import android.content.Context import com.google.gson.Gson import io.novafoundation.nova.common.data.network.NetworkApiCreator +import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.interfaces.FileProvider import io.novafoundation.nova.core_db.dao.ChainAssetDao @@ -29,4 +30,6 @@ interface RuntimeDependencies { fun chainDao(): ChainDao fun chainAssetDao(): ChainAssetDao + + fun assetsIconModeService(): AssetsIconModeService } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt index bed655baa2..f512bb5174 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt @@ -4,6 +4,7 @@ import com.google.gson.Gson import dagger.Module import dagger.Provides import io.novafoundation.nova.common.data.network.rpc.BulkRetriever +import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.ApplicationScope import io.novafoundation.nova.core.storage.StorageCache @@ -265,8 +266,14 @@ class RuntimeModule { @Provides @ApplicationScope - fun provideRemoteToDomainChainMapperFacade(gson: Gson): RemoteToDomainChainMapperFacade { - return RemoteToDomainChainMapperFacade(gson) + fun provideRemoteToDomainChainMapperFacade( + gson: Gson, + assetsIconModeService: AssetsIconModeService + ): RemoteToDomainChainMapperFacade { + return RemoteToDomainChainMapperFacade( + gson, + assetsIconModeService + ) } @Provides diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt index f8c0879a0a..87bb55624d 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt @@ -2,11 +2,11 @@ package io.novafoundation.nova.runtime.multiNetwork import android.util.Log import com.google.gson.Gson +import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.common.utils.LOG_TAG import io.novafoundation.nova.common.utils.diffed import io.novafoundation.nova.common.utils.filterList import io.novafoundation.nova.common.utils.inBackground -import io.novafoundation.nova.common.utils.mapList import io.novafoundation.nova.common.utils.mapNotNullToSet import io.novafoundation.nova.common.utils.removeHexPrefix import io.novafoundation.nova.core.ethereum.Web3Api @@ -40,6 +40,7 @@ import io.novasama.substrate_sdk_android.wsrpc.SocketService import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first @@ -63,11 +64,13 @@ class ChainRegistry( private val baseTypeSynchronizer: BaseTypeSynchronizer, private val runtimeSyncService: RuntimeSyncService, private val web3ApiPool: Web3ApiPool, - private val gson: Gson + private val gson: Gson, + private val assetsIconModeService: AssetsIconModeService ) : CoroutineScope by CoroutineScope(Dispatchers.Default) { - val currentChains = chainDao.joinChainInfoFlow() - .mapList { mapChainLocalToChain(it, gson) } + val currentChains = combine(chainDao.joinChainInfoFlow(), assetsIconModeService.assetsIconModeFlow()) { chains, assetIconMode -> + chains.map { mapChainLocalToChain(it, gson, assetIconMode) } + } .diffed() .map { diff -> diff.removed.forEach { unregisterChain(it) } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/DomainToLocalChainMapper.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/DomainToLocalChainMapper.kt index fb90529a77..29cd0b6451 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/DomainToLocalChainMapper.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/DomainToLocalChainMapper.kt @@ -97,7 +97,7 @@ fun mapChainAssetToLocal(asset: Chain.Asset, gson: Gson): ChainAssetLocal { source = mapAssetSourceToLocal(asset.source), buyProviders = gson.toJson(asset.buyProviders), typeExtras = gson.toJson(typeExtras), - icon = asset.iconUrl, + icon = asset.icon?.name, enabled = asset.enabled ) } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt index 81ce937317..186898f00a 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.runtime.multiNetwork.chain.mappers import android.util.Log import com.google.gson.Gson +import io.novafoundation.nova.common.data.model.AssetIconMode import io.novafoundation.nova.common.utils.asPrecision import io.novafoundation.nova.common.utils.asTokenSymbol import io.novafoundation.nova.common.utils.enumValueOfOrNull @@ -21,6 +22,7 @@ import io.novafoundation.nova.core_db.model.chain.ChainLocal.ConnectionStateLoca import io.novafoundation.nova.core_db.model.chain.ChainNodeLocal import io.novafoundation.nova.core_db.model.chain.JoinedChainInfo import io.novafoundation.nova.core_db.model.chain.NodeSelectionPreferencesLocal +import io.novafoundation.nova.runtime.BuildConfig import io.novafoundation.nova.runtime.multiNetwork.chain.mappers.utils.EVM_TRANSFER_PARAMETER import io.novafoundation.nova.runtime.multiNetwork.chain.mappers.utils.GovernanceReferendaParameters import io.novafoundation.nova.runtime.multiNetwork.chain.mappers.utils.SUBSTRATE_TRANSFER_PARAMETER @@ -182,7 +184,7 @@ private fun mapNodeSelectionFromLocal(nodeSelectionPreferencesLocal: NodeSelecti } } -fun mapChainLocalToChain(chainLocal: JoinedChainInfo, gson: Gson): Chain { +fun mapChainLocalToChain(chainLocal: JoinedChainInfo, gson: Gson, assetIconMode: AssetIconMode): Chain { return mapChainLocalToChain( chainLocal.chain, chainLocal.nodes, @@ -190,7 +192,8 @@ fun mapChainLocalToChain(chainLocal: JoinedChainInfo, gson: Gson): Chain { chainLocal.assets, chainLocal.explorers, chainLocal.externalApis, - gson + gson, + assetIconMode ) } @@ -201,7 +204,8 @@ fun mapChainLocalToChain( assetsLocal: List, explorersLocal: List, externalApisLocal: List, - gson: Gson + gson: Gson, + assetIconMode: AssetIconMode ): Chain { val nodes = nodesLocal.sortedBy { it.orderId }.map { Chain.Node( @@ -219,7 +223,7 @@ fun mapChainLocalToChain( nodes = nodes ) - val assets = assetsLocal.map { mapChainAssetLocalToAsset(it, gson) } + val assets = assetsLocal.map { mapChainAssetLocalToAsset(it, gson, assetIconMode) } val explorers = explorersLocal.map { Chain.Explorer( @@ -274,12 +278,12 @@ fun mapChainLocalToChain( } } -fun mapChainAssetLocalToAsset(local: ChainAssetLocal, gson: Gson): Chain.Asset { +fun mapChainAssetLocalToAsset(local: ChainAssetLocal, gson: Gson, assetIconMode: AssetIconMode): Chain.Asset { val typeExtrasParsed = local.typeExtras?.let(gson::parseArbitraryObject) val buyProviders = local.buyProviders?.let?>(gson::fromJsonOrNull).orEmpty() return Chain.Asset( - iconUrl = local.icon, + icon = getAssetIconUrl(local.icon, assetIconMode), id = local.id, symbol = local.symbol.asTokenSymbol(), precision = local.precision.asPrecision(), @@ -294,6 +298,17 @@ fun mapChainAssetLocalToAsset(local: ChainAssetLocal, gson: Gson): Chain.Asset { ) } +private fun getAssetIconUrl(icon: String?, assetIconMode: AssetIconMode): Chain.Icon? { + return icon?.let { + val baseUrl = when (assetIconMode) { + AssetIconMode.COLORED -> BuildConfig.ASSET_COLORED_ICON_URL + AssetIconMode.WHITE -> BuildConfig.ASSET_WHITE_ICON_URL + } + + Chain.Icon(it, baseUrl) + } +} + private fun mapSourceFromLocal(local: ChainLocal.Source): Chain.Source { return when (local) { ChainLocal.Source.DEFAULT -> Chain.Source.DEFAULT diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt index 0dcaa94782..01e45dae0a 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt @@ -1,13 +1,15 @@ package io.novafoundation.nova.runtime.multiNetwork.chain.mappers import com.google.gson.Gson +import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.core_db.model.chain.ChainLocal import io.novafoundation.nova.core_db.model.chain.NodeSelectionPreferencesLocal import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import io.novafoundation.nova.runtime.multiNetwork.chain.remote.model.ChainRemote class RemoteToDomainChainMapperFacade( - private val gson: Gson + private val gson: Gson, + private val assetsIconModeService: AssetsIconModeService ) { fun mapRemoteChainToDomain(chainRemote: ChainRemote, source: Chain.Source): Chain { @@ -28,7 +30,8 @@ class RemoteToDomainChainMapperFacade( assetsLocal = assetsLocal, explorersLocal = explorersLocal, externalApisLocal = externalApisLocal, - gson = gson + gson = gson, + assetsIconModeService.getIconMode() ) } } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/model/Chain.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/model/Chain.kt index 76b61f9ae2..6ccbdbd207 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/model/Chain.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/model/Chain.kt @@ -46,6 +46,17 @@ data class Chain( val assetsById = assets.associateBy(Asset::id) + data class Icon( + val name: String, + val baseUrl: String, + ) { + companion object; + + constructor(url: String) : this("", url) + + fun getIconUrl(): String = "$baseUrl/$name" + } + data class Additional( val defaultTip: BigInteger?, val themeColor: String?, @@ -65,7 +76,7 @@ data class Chain( ) data class Asset( - val iconUrl: String?, + val icon: Icon?, val id: ChainAssetId, val priceId: String?, val chainId: ChainId, @@ -79,6 +90,9 @@ data class Chain( val enabled: Boolean, ) : Identifiable, Serializable { + // To support legacy code + val iconUrl = icon?.getIconUrl() + enum class Source { DEFAULT, ERC20, MANUAL } From 7ccbd8a1f983c799fcaa1459ae51a68aad2141f9 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 25 Oct 2024 17:30:09 +0200 Subject: [PATCH 24/78] Update TokenAssetMappers.kt --- .../presentation/balance/common/mappers/TokenAssetMappers.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index dbdb8fb6c2..5835ffb989 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -63,7 +63,7 @@ private fun mapAssetGroupToUi( private fun mapType( assetGroup: TokenAssetGroup, assets: List, - groupBalance: (TokenAssetGroup) -> Amount + groupBalance: (TokenAssetGroup) -> PricedAmount ): TokenGroupUi.GroupType { return if (assets.size == 1) { val balance = groupBalance(assetGroup) From 2166f9e6ac27c145f2a7ec05e91975fc7450f2a0 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 25 Oct 2024 17:34:41 +0200 Subject: [PATCH 25/78] Update TokenAssetMappers.kt --- .../balance/common/mappers/TokenAssetMappers.kt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index 89cb16e7e4..36c54cb064 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -60,14 +60,6 @@ private fun mapAssetsToAssetModels( return assets.map { TokenAssetUi(group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } } -fun mapAssetsToAssetModels( - group: TokenGroupUi, - assets: List, - balance: (TotalAndTransferableBalance) -> Amount -): List { - return assets.map { TokenAssetUi(group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } -} - private fun mapType( assetGroup: TokenAssetGroup, assets: List, From 3d37fa56bc22a00aea8f9a1daa044ce5d4d1179b Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 25 Oct 2024 17:45:14 +0200 Subject: [PATCH 26/78] Fixed merge issues --- .../balance/common/mappers/NetworkAssetMappers.kt | 2 +- .../balance/common/mappers/TokenAssetMappers.kt | 6 +++--- .../buy/flow/network/NetworkBuyFlowViewModel.kt | 4 ++-- .../presentation/flow/asset/AssetFlowViewModel.kt | 4 ++-- .../presentation/flow/network/NetworkFlowViewModel.kt | 3 ++- .../receive/flow/network/NetworkReceiveFlowViewModel.kt | 4 ++-- .../presentation/send/flow/asset/AssetSendFlowViewModel.kt | 4 ++-- .../send/flow/network/NetworkSendFlowViewModel.kt | 4 ++-- .../presentation/swap/asset/AssetSwapFlowViewModel.kt | 4 ++-- .../presentation/swap/network/NetworkSwapFlowViewModel.kt | 4 ++-- 10 files changed, 20 insertions(+), 19 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt index fe2df1b365..85be66a4cb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt @@ -32,7 +32,7 @@ private fun mapAssetsToAssetModels( return assets.map { NetworkAssetUi(mapAssetToAssetModel(it.asset, balance(it.balanceWithOffchain))) } } -private fun mapAssetGroupToUi( +fun mapAssetGroupToUi( assetGroup: NetworkAssetGroup, currency: Currency, groupBalance: (NetworkAssetGroup) -> BigDecimal diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index 36c54cb064..39438a2fec 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -21,7 +21,7 @@ fun GroupedList.mapGroupedAssetsToUi( groupBalance: (TokenAssetGroup) -> PricedAmount = { it.groupBalance.total }, balance: (AssetBalance) -> PricedAmount = AssetBalance::total, ): List { - return mapKeys { (group, assets) -> mapAssetGroupToUi(group, assets, groupBalance) } + return mapKeys { (group, assets) -> mapTokenAssetGroupToUi(group, assets, groupBalance) } .mapValues { (group, assets) -> val assetModels = mapAssetsToAssetModels(group, assets, balance) assetFilter(group.itemId, assetModels) @@ -30,10 +30,10 @@ fun GroupedList.mapGroupedAssetsToUi( .filterIsInstance() } -private fun mapAssetGroupToUi( +fun mapTokenAssetGroupToUi( assetGroup: TokenAssetGroup, assets: List, - groupBalance: (TokenAssetGroup) -> PricedAmount + groupBalance: (TokenAssetGroup) -> PricedAmount = { it.groupBalance.total } ): TokenGroupUi { val balance = groupBalance(assetGroup) return TokenGroupUi( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt index d5aa48e258..a8314ccb47 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt @@ -5,8 +5,8 @@ import io.novafoundation.nova.common.utils.TokenSymbol import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.common.Amount import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin @@ -42,7 +42,7 @@ class NetworkBuyFlowViewModel( val buyMixin = buyMixinFactory.create(scope = this) - override fun getAssetBalance(asset: AssetWithNetwork): Amount { + override fun getAssetBalance(asset: AssetWithNetwork): PricedAmount { return asset.balanceWithOffChain.total } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index ec601f43a6..c4e9976e83 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -17,7 +17,7 @@ import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBala import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapAssetGroupToUi +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapTokenAssetGroupToUi import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi @@ -86,7 +86,7 @@ abstract class AssetFlowViewModel( } open fun mapTokensAssets(assets: Map>): List { - return assets.map { mapAssetGroupToUi(it.key, assets = it.value) } + return assets.map { mapTokenAssetGroupToUi(it.key, assets = it.value) } } internal fun validate(assetModel: AssetModel, onAccept: (AssetModel) -> Unit) { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt index f7e873eb27..10c7bc9836 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt @@ -8,6 +8,7 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAcco import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.common.Amount import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin @@ -38,7 +39,7 @@ abstract class NetworkFlowViewModel( val networks: Flow> = assetsFlow(networkFlowPayload.asTokenSymbol()) .map { mapAssets(it) } - abstract fun getAssetBalance(asset: AssetWithNetwork): Amount + abstract fun getAssetBalance(asset: AssetWithNetwork): PricedAmount abstract fun assetsFlow(tokenSymbol: TokenSymbol): Flow> diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt index bcf942eb1d..535dbde27a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt @@ -5,8 +5,8 @@ import io.novafoundation.nova.common.utils.TokenSymbol import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.common.Amount import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin @@ -37,7 +37,7 @@ class NetworkReceiveFlowViewModel( chainRegistry ) { - override fun getAssetBalance(asset: AssetWithNetwork): Amount { + override fun getAssetBalance(asset: AssetWithNetwork): PricedAmount { return asset.balanceWithOffChain.total } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt index 94c438d7f5..9401f1c763 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt @@ -14,7 +14,7 @@ import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetBalance import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapAssetGroupToUi +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapTokenAssetGroupToUi import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi @@ -69,7 +69,7 @@ class AssetSendFlowViewModel( override fun mapTokensAssets(assets: Map>): List { return assets.map { (group, assets) -> - mapAssetGroupToUi(group, assets = assets) { it.groupBalance.transferable } + mapTokenAssetGroupToUi(group, assets = assets) { it.groupBalance.transferable } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt index 8187558da9..31ac3f2e79 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowViewModel.kt @@ -5,7 +5,7 @@ import io.novafoundation.nova.common.utils.TokenSymbol import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter @@ -38,7 +38,7 @@ class NetworkSendFlowViewModel( chainRegistry ) { - override fun getAssetBalance(asset: AssetWithNetwork): Amount { + override fun getAssetBalance(asset: AssetWithNetwork): PricedAmount { return asset.balanceWithOffChain.transferable } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index 21b7b2a45d..63db3e3d28 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -16,7 +16,7 @@ import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetBalance import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin -import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapAssetGroupToUi +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapTokenAssetGroupToUi import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi @@ -97,7 +97,7 @@ class AssetSwapFlowViewModel( override fun mapTokensAssets(assets: Map>): List { return assets.map { (group, assets) -> - mapAssetGroupToUi(group, assets = assets) { it.groupBalance.transferable } + mapTokenAssetGroupToUi(group, assets = assets) { it.groupBalance.transferable } } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt index 93f84fd011..8771188d68 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt @@ -5,7 +5,7 @@ import io.novafoundation.nova.common.utils.TokenSymbol import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.common.Amount +import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter @@ -40,7 +40,7 @@ class NetworkSwapFlowViewModel( chainRegistry ) { - override fun getAssetBalance(asset: AssetWithNetwork): Amount { + override fun getAssetBalance(asset: AssetWithNetwork): PricedAmount { return asset.balanceWithOffChain.transferable } From ed0b2fecb98cae04fb2c56562c1f1de8425e9304 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 25 Oct 2024 17:45:20 +0200 Subject: [PATCH 27/78] Update NetworkFlowViewModel.kt --- .../presentation/flow/network/NetworkFlowViewModel.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt index 10c7bc9836..75dbdeb99b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt @@ -6,7 +6,6 @@ import io.novafoundation.nova.common.utils.TokenSymbol import io.novafoundation.nova.common.utils.flowOf import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.common.Amount import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor From 1902b9f5ae9da9a52b6be3346b12f08bfdd8a433 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 25 Oct 2024 22:08:11 +0200 Subject: [PATCH 28/78] Clean code --- .../data/repository/RealChainAssetRepository.kt | 8 +++++--- .../feature_wallet_impl/di/WalletFeatureDependencies.kt | 3 +++ .../nova/feature_wallet_impl/di/WalletFeatureModule.kt | 6 ++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt index 8e24dd42e8..962ba816eb 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt @@ -1,7 +1,7 @@ package io.novafoundation.nova.feature_wallet_impl.data.repository import com.google.gson.Gson -import io.novafoundation.nova.common.data.model.AssetIconMode +import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.core_db.dao.ChainAssetDao import io.novafoundation.nova.core_db.dao.SetAssetEnabledParams import io.novafoundation.nova.feature_wallet_api.domain.interfaces.ChainAssetRepository @@ -12,7 +12,8 @@ import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId class RealChainAssetRepository( private val chainAssetDao: ChainAssetDao, - private val gson: Gson + private val gson: Gson, + private val assetsIconModeService: AssetsIconModeService ) : ChainAssetRepository { override suspend fun setAssetsEnabled(enabled: Boolean, assetIds: List) { @@ -27,6 +28,7 @@ class RealChainAssetRepository( } override suspend fun getEnabledAssets(): List { - return chainAssetDao.getEnabledAssets().map { mapChainAssetLocalToAsset(it, gson, AssetIconMode.WHITE) } + val iconMode = assetsIconModeService.getIconMode() + return chainAssetDao.getEnabledAssets().map { mapChainAssetLocalToAsset(it, gson, iconMode) } } } diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt index 8b79b7f3eb..02428e750d 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt @@ -8,6 +8,7 @@ import io.novafoundation.nova.common.data.memory.ComputationalCache import io.novafoundation.nova.common.data.network.AppLinksProvider import io.novafoundation.nova.common.data.network.HttpExceptionHandler import io.novafoundation.nova.common.data.network.NetworkApiCreator +import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.data.storage.encrypt.EncryptedPreferences import io.novafoundation.nova.common.interfaces.FileCache @@ -134,6 +135,8 @@ interface WalletFeatureDependencies { fun hydraDxAssetIdConverter(): HydraDxAssetIdConverter + fun assetsIconModeService(): AssetsIconModeService + val fileCache: FileCache val storageCache: StorageCache diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt index c1dbadcdbb..07f4bc9659 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt @@ -6,6 +6,7 @@ import dagger.Provides import io.novafoundation.nova.common.data.memory.ComputationalCache import io.novafoundation.nova.common.data.network.HttpExceptionHandler import io.novafoundation.nova.common.data.network.NetworkApiCreator +import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.FeatureScope import io.novafoundation.nova.common.interfaces.FileCache @@ -322,8 +323,9 @@ class WalletFeatureModule { @FeatureScope fun provideChainAssetRepository( chainAssetDao: ChainAssetDao, - gson: Gson - ): ChainAssetRepository = RealChainAssetRepository(chainAssetDao, gson) + gson: Gson, + assetsIconModeService: AssetsIconModeService + ): ChainAssetRepository = RealChainAssetRepository(chainAssetDao, gson, assetsIconModeService) @Provides @FeatureScope From bc248e6309a0b7bf4b88546896845548c6887034 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Mon, 28 Oct 2024 20:33:34 +0100 Subject: [PATCH 29/78] Receive screen update --- .../nova/common/utils/ContextExt.kt | 4 + .../nova/common/utils/QrCodeGenerator.kt | 9 +- .../nova/common/utils/images/Icon.kt | 6 + .../nova/common/view/QrCodeView.kt | 189 ++++++++++++++++++ common/src/main/res/values/colors.xml | 5 +- common/src/main/res/values/strings.xml | 2 + common/src/main/res/values/styles.xml | 6 +- .../di/AssetsFeatureDependencies.kt | 3 + .../domain/receive/ReceiveInteractor.kt | 5 + .../presentation/receive/ReceiveFragment.kt | 49 ++--- .../presentation/receive/ReceiveViewModel.kt | 83 ++++---- .../presentation/receive/di/ReceiveModule.kt | 13 +- .../src/main/res/layout/fragment_receive.xml | 172 +++++++++++----- .../main/res/layout/item_tinder_gov_card.xml | 2 +- .../runtime/multiNetwork/chain/model/Chain.kt | 2 +- 15 files changed, 427 insertions(+), 123 deletions(-) create mode 100644 common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/ContextExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/ContextExt.kt index c203835eb0..70435e41f6 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/ContextExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/ContextExt.kt @@ -145,3 +145,7 @@ fun Drawable.withRippleMask(mask: Drawable = getRippleMask()) = context.addRippl context(View) val Int.dp: Int get() = dp(this@View.context) + +context(View) +val Int.dpF: Float + get() = dpF(this@View.context) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/QrCodeGenerator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/QrCodeGenerator.kt index 69c08a9d6b..31fbfd5e08 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/QrCodeGenerator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/QrCodeGenerator.kt @@ -4,6 +4,7 @@ import android.graphics.Bitmap import com.google.zxing.EncodeHintType import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import com.google.zxing.qrcode.encoder.Encoder +import com.google.zxing.qrcode.encoder.QRCode import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -22,10 +23,14 @@ class QrCodeGenerator( const val MAX_PAYLOAD_LENGTH = 512 } + fun generateQrCode(input: String): QRCode { + val hints = HashMap() + return Encoder.encode(input, ErrorCorrectionLevel.H, hints) + } + suspend fun generateQrBitmap(input: String): Bitmap { return withContext(Dispatchers.Default) { - val hints = HashMap() - val qrCode = Encoder.encode(input, ErrorCorrectionLevel.H, hints) + val qrCode = generateQrCode(input) val byteMatrix = qrCode.matrix val width = byteMatrix.width + PADDING_SIZE val height = byteMatrix.height + PADDING_SIZE diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/images/Icon.kt b/common/src/main/java/io/novafoundation/nova/common/utils/images/Icon.kt index 54c0b3e420..931caf803f 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/images/Icon.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/images/Icon.kt @@ -40,3 +40,9 @@ fun ImageView.setIconOrMakeGone(icon: Icon?, imageLoader: ImageLoader, builder: fun Drawable.asIcon() = Icon.FromDrawable(this) fun @receiver:DrawableRes Int.asIcon() = Icon.FromDrawableRes(this) fun String.asIcon() = Icon.FromLink(this) + +fun ImageLoader.Companion.formatIcon(icon: Icon): Any = when (icon) { + is Icon.FromDrawable -> icon.data + is Icon.FromDrawableRes -> icon.res + is Icon.FromLink -> icon.data +} diff --git a/common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt b/common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt new file mode 100644 index 0000000000..d98aaf86aa --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt @@ -0,0 +1,189 @@ +package io.novafoundation.nova.common.view + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.RectF +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.view.View +import androidx.core.graphics.toRect +import coil.ImageLoader +import coil.request.ImageRequest +import com.google.zxing.qrcode.encoder.QRCode +import io.novafoundation.nova.common.R +import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.common.utils.dp +import io.novafoundation.nova.common.utils.dpF +import io.novafoundation.nova.common.utils.images.Icon +import io.novafoundation.nova.common.utils.images.formatIcon + +class QrCodeModel( + val qrCode: QRCode, + val overlayBackground: Drawable?, + val overlayPaddingInDp: Int, + val centerOverlay: Icon?, +) + +class QrCodeView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : View(context, attrs, defStyleAttr) { + + private val qrColor = context.getColor(R.color.qr_code_content) + private val backgroundColor = context.getColor(R.color.qr_code_background) + private val paint = Paint(Paint.ANTI_ALIAS_FLAG) + + private var data: QRCode? = null + + private var overlayPadding: Int = 0 + private var centerOverlay: Drawable? = null + private var overlayBackground: Drawable? = null + + private val overlaySize = 64.dp + private val overlayQuiteZone = 4.dp + private val qrPadding = 16.dpF + + private val centerRect: RectF = RectF() + + private val imageLoader: ImageLoader by lazy(LazyThreadSafetyMode.NONE) { + if (isInEditMode) { + ImageLoader.invoke(context) + } else { + FeatureUtils.getCommonApi(context).imageLoader() + } + } + + fun setQrModel(model: QrCodeModel) { + this.data = model.qrCode + this.overlayBackground = model.overlayBackground + this.overlayPadding = model.overlayPaddingInDp.dp(context) + + if (model.centerOverlay != null) { + val centerOverlayRequest = getCenterOverlayImageRequest(model.centerOverlay) { + this.centerOverlay = it + invalidate() + } + + imageLoader.enqueue(centerOverlayRequest) + } + invalidate() + } + + private fun getCenterOverlayImageRequest(icon: Icon, target: (Drawable?) -> Unit): ImageRequest { + return ImageRequest.Builder(context) + .data(ImageLoader.formatIcon(icon)) + .target(onSuccess = target) + .size(overlaySize, overlaySize) + .build() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val widthSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSize = MeasureSpec.getSize(heightMeasureSpec) + + setMeasuredDimension(widthSize, heightSize) + + centerRect.left = (measuredWidth / 2 - overlaySize / 2).toFloat() + centerRect.top = (measuredHeight / 2 - overlaySize / 2).toFloat() + centerRect.right = (measuredWidth / 2 + overlaySize / 2).toFloat() + centerRect.bottom = (measuredHeight / 2 + overlaySize / 2).toFloat() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + canvas.save() + + paint.color = qrColor + canvas.drawColor(backgroundColor) + data?.let { renderQRCodeImage(canvas, it) } + + canvas.restore() + } + + private fun renderQRCodeImage(canvas: Canvas, data: QRCode) { + renderQRImage(canvas, data, width, height) + } + + private fun renderQRImage(canvas: Canvas, code: QRCode, width: Int, height: Int) { + paint.color = qrColor + val input = code.matrix ?: throw IllegalStateException() + val inputWidth = input.width + val inputHeight = input.height + val outputWidth = Math.max(width, inputWidth) - qrPadding * 2 + val outputHeight = Math.max(height, inputHeight) - qrPadding * 2 + val multiple = Math.min(outputWidth / inputWidth, outputHeight / inputHeight) + val leftPadding = qrPadding + val topPadding = qrPadding + val FINDER_PATTERN_SIZE = 7f + val CIRCLE_SCALE_DOWN_FACTOR = 0.7f + val circleSize = (multiple * CIRCLE_SCALE_DOWN_FACTOR) + val circleRadius = circleSize / 2 + + var inputY = 0 + var outputY = topPadding + + while (inputY < inputHeight) { + var inputX = 0 + var outputX = leftPadding + while (inputX < inputWidth) { + if (input[inputX, inputY].toInt() == 1) { + val overlaysFinder = inputX <= FINDER_PATTERN_SIZE && inputY <= FINDER_PATTERN_SIZE || + inputX >= inputWidth - FINDER_PATTERN_SIZE && inputY <= FINDER_PATTERN_SIZE || + inputX <= FINDER_PATTERN_SIZE && inputY >= inputHeight - FINDER_PATTERN_SIZE + + val overlaysCenter = (this.overlay != null) && ( + this.centerRect.intersects( + outputX - overlayQuiteZone, + outputY - overlayQuiteZone, + outputX + circleSize + overlayQuiteZone, + outputY + circleRadius + overlayQuiteZone + ) + ) + + if (!overlaysCenter && !overlaysFinder) { + canvas.drawCircle(paddingStart + outputX + circleRadius, paddingStart + outputY + circleRadius, circleRadius, paint) + } + } + inputX++ + outputX += multiple + } + inputY++ + outputY += multiple + } + val cornerCircleDiameter = multiple * FINDER_PATTERN_SIZE + drawFinderPatternCircleStyle(canvas, leftPadding, topPadding, cornerCircleDiameter) + drawFinderPatternCircleStyle(canvas, leftPadding + (inputWidth - FINDER_PATTERN_SIZE) * multiple, topPadding, cornerCircleDiameter) + drawFinderPatternCircleStyle(canvas, leftPadding, topPadding + (inputHeight - FINDER_PATTERN_SIZE) * multiple, cornerCircleDiameter) + + drawCenterOverlay(canvas) + } + + private fun drawFinderPatternCircleStyle(canvas: Canvas, x: Float, y: Float, circleDiameter: Float) { + val radius = circleDiameter / 2 + val WHITE_CIRCLE_RADIUS = circleDiameter * 5 / 7 / 2 + val WHITE_CIRCLE_OFFSET = circleDiameter / 7 + WHITE_CIRCLE_RADIUS + val MIDDLE_DOT_RADIUS = circleDiameter * 3 / 7 / 2 + val MIDDLE_DOT_OFFSET = circleDiameter * 2 / 7 + MIDDLE_DOT_RADIUS + paint.color = qrColor + canvas.drawCircle(x + radius, y + radius, radius, paint) + paint.color = backgroundColor + canvas.drawCircle(x + WHITE_CIRCLE_OFFSET, y + WHITE_CIRCLE_OFFSET, WHITE_CIRCLE_RADIUS, paint) + paint.color = qrColor + canvas.drawCircle(x + MIDDLE_DOT_OFFSET, y + MIDDLE_DOT_OFFSET, MIDDLE_DOT_RADIUS, paint) + } + + private fun drawCenterOverlay(canvas: Canvas) { + val overlayBackgroundWithInsets = centerRect.toRect().apply { + inset(overlayPadding, overlayPadding) + } + + overlayBackground?.bounds = overlayBackgroundWithInsets + centerOverlay?.bounds = overlayBackgroundWithInsets + + overlayBackground?.draw(canvas) + centerOverlay?.draw(canvas) + } +} diff --git a/common/src/main/res/values/colors.xml b/common/src/main/res/values/colors.xml index 7bcdb91c89..409cd3792e 100644 --- a/common/src/main/res/values/colors.xml +++ b/common/src/main/res/values/colors.xml @@ -3,6 +3,7 @@ #eeeeee #FFFFFF + #101014 #05081C @@ -13,8 +14,10 @@ #E0FFFFFF - #05081C + #000000 #7AFFFFFF + #8F000000 + #05081C #E0FFFFFF #A3FFFFFF #52FFFFFF diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index ebda8576ce..27f7606438 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -1,6 +1,8 @@ + Send only %1$s token and tokens in %2$s network to this address, or you might lose your funds + Select network for buying %s Select network for receiving %s Select network for sending %s diff --git a/common/src/main/res/values/styles.xml b/common/src/main/res/values/styles.xml index c9f36fd1b8..63d87457d5 100644 --- a/common/src/main/res/values/styles.xml +++ b/common/src/main/res/values/styles.xml @@ -457,10 +457,14 @@ @color/selector_button_background_secondary - + + diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt index ee8bc8885c..1daad3404e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt @@ -10,6 +10,7 @@ import io.novafoundation.nova.common.data.network.AppLinksProvider import io.novafoundation.nova.common.data.network.HttpExceptionHandler import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser +import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.common.data.repository.AssetsViewModeService import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.data.storage.Preferences @@ -174,6 +175,8 @@ interface AssetsFeatureDependencies { fun walletConnectSessionsUseCase(): WalletConnectSessionsUseCase + fun assetsIconModeService(): AssetsIconModeService + val assetsSourceRegistry: AssetSourceRegistry fun nftRepository(): NftRepository diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/receive/ReceiveInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/receive/ReceiveInteractor.kt index a5638bd8a1..e7b9fd6427 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/receive/ReceiveInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/receive/ReceiveInteractor.kt @@ -2,6 +2,8 @@ package io.novafoundation.nova.feature_assets.domain.receive import android.graphics.Bitmap import android.net.Uri +import io.novafoundation.nova.common.data.model.AssetIconMode +import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.common.interfaces.FileProvider import io.novafoundation.nova.common.utils.write import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository @@ -16,6 +18,7 @@ class ReceiveInteractor( private val fileProvider: FileProvider, private val chainRegistry: ChainRegistry, private val accountRepository: AccountRepository, + private val assetsIconModeService: AssetsIconModeService ) { suspend fun getQrCodeSharingString(chainId: ChainId): String = withContext(Dispatchers.Default) { @@ -25,6 +28,8 @@ class ReceiveInteractor( accountRepository.createQrAccountContent(chain, account) } + fun getAssetIconMode(): AssetIconMode = assetsIconModeService.getIconMode() + suspend fun generateTempQrFile(qrCode: Bitmap): Result = withContext(Dispatchers.IO) { runCatching { val file = fileProvider.generateTempFile(fixedName = QR_FILE_NAME) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt index 21a865ae63..85a04af92b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt @@ -4,23 +4,29 @@ import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup +import androidx.core.view.drawToBitmap import coil.ImageLoader import io.novafoundation.nova.common.base.BaseFragment import io.novafoundation.nova.common.di.FeatureUtils -import io.novafoundation.nova.common.utils.setVisible +import io.novafoundation.nova.common.utils.applyStatusBarInsets import io.novafoundation.nova.common.view.shape.getRoundedCornerDrawable -import io.novafoundation.nova.feature_account_api.presenatation.actions.setupExternalActions -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.receive.model.QrSharingPayload -import kotlinx.android.synthetic.main.fragment_receive.receiveFrom import kotlinx.android.synthetic.main.fragment_receive.receiveQrCode import kotlinx.android.synthetic.main.fragment_receive.receiveShare -import kotlinx.android.synthetic.main.fragment_receive.receiveToolbar import javax.inject.Inject +import kotlinx.android.synthetic.main.fragment_receive.receiveAccount +import kotlinx.android.synthetic.main.fragment_receive.receiveAddress +import kotlinx.android.synthetic.main.fragment_receive.receiveBackButton +import kotlinx.android.synthetic.main.fragment_receive.receiveChain +import kotlinx.android.synthetic.main.fragment_receive.receiveCopyButton +import kotlinx.android.synthetic.main.fragment_receive.receiveQrCodeContainer +import kotlinx.android.synthetic.main.fragment_receive.receiveSubtitle +import kotlinx.android.synthetic.main.fragment_receive.receiveTitle +import kotlinx.android.synthetic.main.fragment_receive.receiveToolbar private const val KEY_PAYLOAD = "KEY_PAYLOAD" @@ -43,16 +49,19 @@ class ReceiveFragment : BaseFragment() { ) = layoutInflater.inflate(R.layout.fragment_receive, container, false) override fun initViews() { - receiveFrom.setWholeClickListener { viewModel.recipientClicked() } + receiveToolbar.applyStatusBarInsets() - receiveToolbar.setHomeButtonListener { viewModel.backClicked() } + receiveCopyButton.setOnClickListener { viewModel.copyAddressClicked() } - receiveShare.setOnClickListener { viewModel.shareButtonClicked() } + receiveBackButton.setOnClickListener { viewModel.backClicked() } - receiveFrom.primaryIcon.setVisible(true) + receiveShare.setOnClickListener { + val qrBitmap = receiveQrCode.drawToBitmap() + viewModel.shareButtonClicked(qrBitmap) + } - receiveQrCode.background = requireContext().getRoundedCornerDrawable(fillColorRes = R.color.qr_code_background) - receiveQrCode.clipToOutline = true // for round corners + receiveQrCodeContainer.background = requireContext().getRoundedCornerDrawable(fillColorRes = R.color.qr_code_background) + receiveQrCodeContainer.clipToOutline = true } override fun inject() { @@ -66,18 +75,12 @@ class ReceiveFragment : BaseFragment() { } override fun subscribe(viewModel: ReceiveViewModel) { - setupExternalActions(viewModel) - - viewModel.qrBitmapFlow.observe(receiveQrCode::setImageBitmap) - - viewModel.receiver.observe { - receiveFrom.setTextIcon(it.addressModel.image) - receiveFrom.primaryIcon.loadTokenIcon(it.chainAssetIcon, imageLoader) - receiveFrom.setMessage(it.addressModel.address) - receiveFrom.setLabel(it.chain.name) - } - - viewModel.toolbarTitle.observe(receiveToolbar::setTitle) + viewModel.chainFlow.observe(receiveChain::setChain) + viewModel.titleFlow.observe(receiveTitle::setText) + viewModel.subtitleFlow.observe(receiveSubtitle::setText) + viewModel.qrCodeFlow.observe(receiveQrCode::setQrModel) + viewModel.accountNameFlow.observe(receiveAccount::setText) + viewModel.addressFlow.observe(receiveAddress::setText) viewModel.shareEvent.observeEvent(::startQrSharingIntent) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt index c0f8b830f1..294f46e498 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt @@ -1,28 +1,28 @@ package io.novafoundation.nova.feature_assets.presentation.receive +import android.graphics.Bitmap import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.data.model.AssetIconMode +import io.novafoundation.nova.common.resources.ClipboardManager import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.Event import io.novafoundation.nova.common.utils.QrCodeGenerator import io.novafoundation.nova.common.utils.flowOf -import io.novafoundation.nova.common.utils.inBackground import io.novafoundation.nova.common.utils.invoke import io.novafoundation.nova.common.utils.lazyAsync +import io.novafoundation.nova.common.view.QrCodeModel import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_account_api.domain.model.addressIn -import io.novafoundation.nova.feature_account_api.presenatation.account.icon.createAddressModel -import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions +import io.novafoundation.nova.feature_account_api.presenatation.chain.icon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.receive.ReceiveInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.receive.model.QrSharingPayload -import io.novafoundation.nova.feature_assets.presentation.receive.model.TokenReceiver import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import io.novafoundation.nova.runtime.multiNetwork.chainWithAsset @@ -30,71 +30,76 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch +private const val COLORED_OVERLAY_PADDING_DP = 0 +private const val WHITE_OVERLAY_PADDING_DP = 8 + class ReceiveViewModel( private val interactor: ReceiveInteractor, private val qrCodeGenerator: QrCodeGenerator, - private val addressIconGenerator: AddressIconGenerator, private val resourceManager: ResourceManager, - private val externalActions: ExternalActions.Presentation, private val assetPayload: AssetPayload, private val chainRegistry: ChainRegistry, selectedAccountUseCase: SelectedAccountUseCase, private val router: AssetsRouter, -) : BaseViewModel(), ExternalActions by externalActions { + private val clipboardManager: ClipboardManager +) : BaseViewModel() { private val selectedMetaAccountFlow = selectedAccountUseCase.selectedMetaAccountFlow() + .shareInBackground() private val chainWithAssetAsync by lazyAsync { chainRegistry.chainWithAsset(assetPayload.chainId, assetPayload.chainAssetId) } - val qrBitmapFlow = flowOf { - val qrString = interactor.getQrCodeSharingString(assetPayload.chainId) + val chainFlow = flowOf { mapChainToUi(chainWithAssetAsync().chain) } - qrCodeGenerator.generateQrBitmap(qrString) + val titleFlow = flowOf { + val (_, chainAsset) = chainWithAssetAsync() + resourceManager.getString(R.string.wallet_asset_receive_token, chainAsset.symbol) } - .inBackground() - .share() - - val receiver = selectedMetaAccountFlow - .map { - val (chain, chainAsset) = chainWithAssetAsync() - val address = it.addressIn(chain)!! - - TokenReceiver( - addressModel = addressIconGenerator.createAddressModel(chain, address, AddressIconGenerator.SIZE_BIG, it.name), - chain = mapChainToUi(chain), - chainAssetIcon = chainAsset.iconUrl - ) - } - .inBackground() - .share() - val toolbarTitle = flowOf { - val (_, chainAsset) = chainWithAssetAsync() + val subtitleFlow = flowOf { + val (chain, chainAsset) = chainWithAssetAsync() + resourceManager.getString(R.string.wallet_asset_receive_token_subtitle, chainAsset.symbol, chain.name) + } - resourceManager.getString(R.string.wallet_asset_receive_token, chainAsset.symbol) + val qrCodeFlow = flowOf { + val assetIconMode = interactor.getAssetIconMode() + val qrInput = interactor.getQrCodeSharingString(assetPayload.chainId) + + val (overlayPadding, overlayBackground) = when (assetIconMode) { + AssetIconMode.COLORED -> COLORED_OVERLAY_PADDING_DP to null + AssetIconMode.WHITE -> WHITE_OVERLAY_PADDING_DP to resourceManager.getDrawable(R.drawable.bg_common_circle) + } + + QrCodeModel( + qrCodeGenerator.generateQrCode(qrInput), + overlayBackground, + overlayPadding, + chainWithAssetAsync().asset.icon() + ) } - .inBackground() - .share() + + val accountNameFlow = selectedMetaAccountFlow.map { it.name } + + val addressFlow = selectedMetaAccountFlow.map { it.addressIn(chainWithAssetAsync().chain)!! } private val _shareEvent = MutableLiveData>() val shareEvent: LiveData> = _shareEvent - fun recipientClicked() = launch { - val accountAddress = receiver.first().addressModel.address - val (chain, _) = chainWithAssetAsync() + fun copyAddressClicked() = launch { + val accountAddress = addressFlow.first() + clipboardManager.addToClipboard(accountAddress) - externalActions.showExternalActions(ExternalActions.Type.Address(accountAddress), chain) + showToast(resourceManager.getString(io.novafoundation.nova.common.R.string.common_copied)) } fun backClicked() { router.back() } - fun shareButtonClicked() = launch { - val qrBitmap = qrBitmapFlow.first() - val address = receiver.first().addressModel.address + fun shareButtonClicked(qrBitmap: Bitmap) = launch { + val address = addressFlow.first() val (chain, chainAsset) = chainWithAssetAsync() viewModelScope.launch { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt index 52d8931d6c..96b9dfd349 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt @@ -6,16 +6,16 @@ import androidx.lifecycle.ViewModelProvider import dagger.Module import dagger.Provides import dagger.multibindings.IntoMap -import io.novafoundation.nova.common.address.AddressIconGenerator +import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule import io.novafoundation.nova.common.interfaces.FileProvider +import io.novafoundation.nova.common.resources.ClipboardManager import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.QrCodeGenerator import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase -import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions import io.novafoundation.nova.feature_assets.domain.receive.ReceiveInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.AssetsRouter @@ -31,7 +31,8 @@ class ReceiveModule { fileProvider: FileProvider, chainRegistry: ChainRegistry, accountRepository: AccountRepository, - ) = ReceiveInteractor(fileProvider, chainRegistry, accountRepository) + assetsIconModeService: AssetsIconModeService + ) = ReceiveInteractor(fileProvider, chainRegistry, accountRepository, assetsIconModeService) @Provides @IntoMap @@ -39,24 +40,22 @@ class ReceiveModule { fun provideViewModel( interactor: ReceiveInteractor, qrCodeGenerator: QrCodeGenerator, - addressIconGenerator: AddressIconGenerator, resourceManager: ResourceManager, - externalActions: ExternalActions.Presentation, router: AssetsRouter, chainRegistry: ChainRegistry, selectedAccountUseCase: SelectedAccountUseCase, payload: AssetPayload, + clipboardManager: ClipboardManager ): ViewModel { return ReceiveViewModel( interactor, qrCodeGenerator, - addressIconGenerator, resourceManager, - externalActions, payload, chainRegistry, selectedAccountUseCase, router, + clipboardManager ) } diff --git a/feature-assets/src/main/res/layout/fragment_receive.xml b/feature-assets/src/main/res/layout/fragment_receive.xml index 0a7f251496..425ea9eeb3 100644 --- a/feature-assets/src/main/res/layout/fragment_receive.xml +++ b/feature-assets/src/main/res/layout/fragment_receive.xml @@ -1,68 +1,144 @@ - + android:layout_height="match_parent" + android:orientation="vertical"> - + android:paddingTop="4dp" + android:paddingBottom="4dp"> - + android:layout_marginStart="8dp" + android:padding="8dp" + android:src="@drawable/ic_arrow_back" + app:tint="@color/icon_primary" /> - + android:layout_gravity="center" /> + + + + + + + + + + + android:layout_marginTop="8dp" + android:ellipsize="end" + android:gravity="center_horizontal" + android:maxLines="1" + android:paddingHorizontal="16dp" + android:textColor="@color/text_primary_on_content" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/receiveQrCode" + tools:text="🌌 NOVA" /> - + android:layout_gravity="center_horizontal" + android:layout_marginHorizontal="16dp" + android:layout_marginTop="8dp" + android:gravity="center_horizontal" + android:paddingHorizontal="16dp" + android:textColor="@color/text_secondary_on_content" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/receiveAccount" + tools:text="Day71BAT8tLr1u43yUV2pKDZE6BvFWrXqFNzMdSHz6iRMAZxKuSr" /> - - - + + + + + + + + diff --git a/feature-governance-impl/src/main/res/layout/item_tinder_gov_card.xml b/feature-governance-impl/src/main/res/layout/item_tinder_gov_card.xml index 886ed927cd..4c9b602f81 100644 --- a/feature-governance-impl/src/main/res/layout/item_tinder_gov_card.xml +++ b/feature-governance-impl/src/main/res/layout/item_tinder_gov_card.xml @@ -84,7 +84,7 @@ Date: Tue, 29 Oct 2024 14:02:47 +0100 Subject: [PATCH 30/78] Fix pr notes --- .../repository/AssetsViewModeRepository.kt | 8 + .../{KEY_PAYLOAD.kt => PayloadCreator.kt} | 16 +- .../feature_assets/di/AssetsFeatureModule.kt | 28 ++- .../assets/models/AssetFlowSearchResult.kt | 5 +- .../assets/search/AssetSearchInteractor.kt | 216 +----------------- .../assets/search/AssetSearchUseCase.kt | 58 +++++ ...setViewModeAssetSearchInteractorFactory.kt | 26 +++ .../search/ByNetworkAssetSearchInteractor.kt | 116 ++++++++++ .../search/ByTokensAssetSearchInteractor.kt | 117 ++++++++++ .../networks/AssetNetworksInteractor.kt | 55 ++--- .../common/mappers/TokenAssetMappers.kt | 2 +- .../balance/search/AssetSearchViewModel.kt | 12 +- .../balance/search/di/AssetSearchModule.kt | 6 +- .../buy/flow/asset/AssetBuyFlowViewModel.kt | 6 +- .../buy/flow/asset/di/AssetBuyFlowModule.kt | 6 +- .../flow/network/NetworkBuyFlowFragment.kt | 8 +- .../flow/network/NetworkBuyFlowViewModel.kt | 2 +- .../flow/asset/AssetFlowViewModel.kt | 11 +- .../flow/network/NetworkFlowViewModel.kt | 8 +- .../flow/asset/AssetReceiveFlowViewModel.kt | 6 +- .../flow/asset/di/AssetReceiveFlowModule.kt | 6 +- .../network/NetworkReceiveFlowFragment.kt | 8 +- .../network/NetworkReceiveFlowViewModel.kt | 2 +- .../send/flow/asset/AssetSendFlowViewModel.kt | 6 +- .../send/flow/asset/di/AssetSendFlowModule.kt | 6 +- .../flow/network/NetworkSendFlowFragment.kt | 8 +- .../swap/asset/AssetSwapFlowViewModel.kt | 7 +- .../swap/asset/di/AssetSwapFlowModule.kt | 6 +- .../swap/network/NetworkSwapFlowFragment.kt | 7 +- .../swap/network/NetworkSwapFlowViewModel.kt | 3 +- 30 files changed, 455 insertions(+), 316 deletions(-) rename common/src/main/java/io/novafoundation/nova/common/utils/{KEY_PAYLOAD.kt => PayloadCreator.kt} (57%) create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchUseCase.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetViewModeAssetSearchInteractorFactory.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByNetworkAssetSearchInteractor.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt diff --git a/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt b/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt index d1438523eb..072c9cbcf1 100644 --- a/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt +++ b/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt @@ -8,7 +8,11 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext interface AssetsViewModeRepository { + + fun getAssetViewMode(): AssetViewMode + fun assetsViewModeFlow(): Flow + suspend fun setAssetsViewMode(assetsViewMode: AssetViewMode) } @@ -19,6 +23,10 @@ class RealAssetsViewModeRepository( private val preferences: Preferences ) : AssetsViewModeRepository { + override fun getAssetViewMode(): AssetViewMode { + return preferences.getString(PREFS_ASSETS_VIEW_MODE)?.fromPrefsValue() ?: ASSET_VIEW_MODE_DEFAULT + } + override fun assetsViewModeFlow(): Flow { return preferences.stringFlow(PREFS_ASSETS_VIEW_MODE) .map { diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/KEY_PAYLOAD.kt b/common/src/main/java/io/novafoundation/nova/common/utils/PayloadCreator.kt similarity index 57% rename from common/src/main/java/io/novafoundation/nova/common/utils/KEY_PAYLOAD.kt rename to common/src/main/java/io/novafoundation/nova/common/utils/PayloadCreator.kt index 2201168910..7b941fd5e3 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/KEY_PAYLOAD.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/PayloadCreator.kt @@ -2,7 +2,7 @@ package io.novafoundation.nova.common.utils import android.os.Bundle import android.os.Parcelable -import androidx.fragment.app.Fragment +import io.novafoundation.nova.common.base.BaseFragment const val KEY_PAYLOAD = "KEY_PAYLOAD" @@ -20,16 +20,6 @@ class FragmentPayloadCreator : PayloadCreator { } } -interface PayloadHolder { - - val payload: T -} - -interface FragmentPayloadHolder : PayloadHolder { - - override val payload: T - get() { - require(this is Fragment) - return requireArguments().getParcelable(KEY_PAYLOAD)!! - } +fun BaseFragment<*>.payload(): T { + return requireArguments().getParcelable(KEY_PAYLOAD)!! } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt index 62aff76073..ac85f5d176 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt @@ -24,7 +24,9 @@ import io.novafoundation.nova.feature_assets.domain.WalletInteractor import io.novafoundation.nova.feature_assets.domain.WalletInteractorImpl import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.RealExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchUseCase +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetViewModeAssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin @@ -58,22 +60,28 @@ class AssetsFeatureModule { @Provides @FeatureScope - fun provideSearchInteractor( + fun provideAssetSearchUseCase( walletRepository: WalletRepository, accountRepository: AccountRepository, chainRegistry: ChainRegistry, - swapService: SwapService, - assetsViewModeRepository: AssetsViewModeRepository - ) = AssetSearchInteractor(walletRepository, accountRepository, chainRegistry, swapService, assetsViewModeRepository) + swapService: SwapService + ) = AssetSearchUseCase(walletRepository, accountRepository, chainRegistry, swapService) + + @Provides + @FeatureScope + fun provideSearchInteractorFactory( + assetViewModeRepository: AssetsViewModeRepository, + assetSearchUseCase: AssetSearchUseCase, + chainRegistry: ChainRegistry + ): AssetSearchInteractorFactory = AssetViewModeAssetSearchInteractorFactory(assetViewModeRepository, assetSearchUseCase, chainRegistry) @Provides @FeatureScope fun provideAssetNetworksInteractor( - walletRepository: WalletRepository, - accountRepository: AccountRepository, chainRegistry: ChainRegistry, - swapService: SwapService - ) = AssetNetworksInteractor(walletRepository, accountRepository, chainRegistry, swapService) + swapService: SwapService, + assetSearchUseCase: AssetSearchUseCase + ) = AssetNetworksInteractor(chainRegistry, swapService, assetSearchUseCase) @Provides @FeatureScope @@ -158,6 +166,7 @@ class AssetsFeatureModule { ) @Provides + @FeatureScope fun provideInitialSwapFlowExecutor( assetsRouter: AssetsRouter ): InitialSwapFlowExecutor { @@ -165,6 +174,7 @@ class AssetsFeatureModule { } @Provides + @FeatureScope fun provideSwapExecutor( initialSwapFlowExecutor: InitialSwapFlowExecutor, assetsRouter: AssetsRouter, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt index 724d4686cf..e0067b0813 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_assets.domain.assets.models +import io.novafoundation.nova.common.utils.MultiMapList import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup @@ -7,9 +8,9 @@ import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup sealed interface AssetFlowSearchResult { - class ByNetworks(val assets: Map>) : AssetFlowSearchResult + class ByNetworks(val assets: MultiMapList) : AssetFlowSearchResult - class ByTokens(val tokens: Map>) : AssetFlowSearchResult + class ByTokens(val tokens: MultiMapList) : AssetFlowSearchResult } fun AssetFlowSearchResult.groupList(): List { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt index 68024957a7..4d39ae339e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt @@ -1,237 +1,45 @@ package io.novafoundation.nova.feature_assets.domain.assets.search -import io.novafoundation.nova.common.data.model.AssetViewMode -import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository -import io.novafoundation.nova.common.utils.flowOfAll -import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult -import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork -import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup -import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance -import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup -import io.novafoundation.nova.feature_assets.domain.common.getAssetBaseComparator -import io.novafoundation.nova.feature_assets.domain.common.getAssetGroupBaseComparator -import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetBaseComparator -import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetGroupBaseComparator -import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByNetwork -import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByToken -import io.novafoundation.nova.feature_assets.domain.common.searchTokens -import io.novafoundation.nova.feature_swap_api.domain.swap.SwapService -import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletRepository import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance -import io.novafoundation.nova.feature_wallet_api.domain.model.aggregatedBalanceByAsset -import io.novafoundation.nova.runtime.ext.fullId -import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry -import io.novafoundation.nova.runtime.multiNetwork.ChainsById -import io.novafoundation.nova.runtime.multiNetwork.asset import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId -import io.novafoundation.nova.runtime.multiNetwork.enabledChainById -import io.novasama.substrate_sdk_android.hash.isPositive import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.flow.map -private typealias AssetSearchFilter = suspend (Asset) -> Boolean +interface AssetSearchInteractorFactory { -class AssetSearchInteractor( - private val walletRepository: WalletRepository, - private val accountRepository: AccountRepository, - private val chainRegistry: ChainRegistry, - private val swapService: SwapService, - private val assetsViewModeRepository: AssetsViewModeRepository -) { + fun createByAssetViewMode(): AssetSearchInteractor +} + +typealias AssetSearchFilter = suspend (Asset) -> Boolean + +interface AssetSearchInteractor { fun buyAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow { - val filter = { asset: Asset -> asset.token.configuration.buyProviders.isNotEmpty() } - - return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> - when (viewMode) { - AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = filter) - .map { AssetFlowSearchResult.ByNetworks(it) } - - AssetViewMode.TOKENS -> searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = filter) - .map { AssetFlowSearchResult.ByTokens(it) } - } - } - } + ): Flow fun sendAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow { - val filter = { asset: Asset -> asset.transferableInPlanks.isPositive() } - - return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> - when (viewMode) { - AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow( - queryFlow, - externalBalancesFlow, - assetGroupComparator = getAssetGroupBaseComparator { it.groupTransferableBalanceFiat }, - assetsComparator = getAssetBaseComparator { it.balanceWithOffchain.transferable.fiat }, - filter = filter - ).map { AssetFlowSearchResult.ByNetworks(it) } - - AssetViewMode.TOKENS -> searchAssetsByTokensInternalFlow( - queryFlow, - externalBalancesFlow, - assetGroupComparator = getTokenAssetGroupBaseComparator { it.groupBalance.transferable.fiat }, - assetsComparator = getTokenAssetBaseComparator { it.balanceWithOffChain.transferable.fiat }, - filter = filter - ) - .map { AssetFlowSearchResult.ByTokens(it) } - } - } - } + ): Flow fun searchSwapAssetsFlow( forAsset: FullChainAssetId?, queryFlow: Flow, externalBalancesFlow: Flow>, coroutineScope: CoroutineScope - ): Flow { - val filterFlow = getAvailableSwapAssets(forAsset, coroutineScope).map { availableAssetsForSwap -> - val filter: AssetSearchFilter = { asset -> - val chainAsset = asset.token.configuration - - chainAsset.fullId in availableAssetsForSwap - } - - filter - } - - return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> - when (viewMode) { - AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filterFlow = filterFlow) - .map { AssetFlowSearchResult.ByNetworks(it) } - - AssetViewMode.TOKENS -> searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filterFlow = filterFlow) - .map { AssetFlowSearchResult.ByTokens(it) } - } - } - } + ): Flow fun searchReceiveAssetsFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow { - return assetsViewModeRepository.assetsViewModeFlow().flatMapLatest { viewMode -> - when (viewMode) { - AssetViewMode.NETWORKS -> searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = null) - .map { AssetFlowSearchResult.ByNetworks(it) } - - AssetViewMode.TOKENS -> searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = null) - .map { AssetFlowSearchResult.ByTokens(it) } - } - } - } + ): Flow fun searchAssetsFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow>> { - return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = null) - } - - fun searchAssetsByNetworksInternalFlow( - queryFlow: Flow, - externalBalancesFlow: Flow>, - assetGroupComparator: Comparator = getAssetGroupBaseComparator(), - assetsComparator: Comparator = getAssetBaseComparator(), - filterFlow: Flow, - ): Flow>> { - val assetsFlow = filteredAssetFlow(filterFlow) - - val aggregatedExternalBalances = externalBalancesFlow.map { it.aggregatedBalanceByAsset() } - - return combine(assetsFlow, aggregatedExternalBalances, queryFlow) { assets, externalBalances, query -> - val chainsById = chainRegistry.enabledChainById() - val filtered = assets.filterBy(query, chainsById) - - groupAndSortAssetsByNetwork(filtered, externalBalances, chainsById, assetGroupComparator, assetsComparator) - } - } - - fun searchAssetsByTokensInternalFlow( - queryFlow: Flow, - externalBalancesFlow: Flow>, - assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), - assetsComparator: Comparator = getTokenAssetBaseComparator(), - filterFlow: Flow, - ): Flow>> { - val assetsFlow = filteredAssetFlow(filterFlow) - - val aggregatedExternalBalances = externalBalancesFlow.map { it.aggregatedBalanceByAsset() } - - return combine(assetsFlow, aggregatedExternalBalances, queryFlow) { assets, externalBalances, query -> - val chainsById = chainRegistry.enabledChainById() - val filtered = assets.filterBy(query, chainsById) - - groupAndSortAssetsByToken(filtered, externalBalances, chainsById, assetGroupComparator, assetsComparator) - } - } - - private fun filteredAssetFlow(filterFlow: Flow): Flow> { - val assetsFlow = accountRepository.selectedMetaAccountFlow() - .flatMapLatest { walletRepository.syncedAssetsFlow(it.id) } - - return combine(assetsFlow, filterFlow) { assets, filter -> - if (filter == null) { - assets - } else { - assets.filter { filter(it) } - } - } - } - - private fun getAvailableSwapAssets(asset: FullChainAssetId?, coroutineScope: CoroutineScope): Flow> { - return flowOfAll { - val chainAsset = asset?.let { chainRegistry.asset(it) } - - if (chainAsset == null) { - swapService.assetsAvailableForSwap(coroutineScope) - } else { - swapService.availableSwapDirectionsFor(chainAsset, coroutineScope) - } - } - } - - private fun List.filterBy(query: String, chainsById: ChainsById): List { - return searchTokens( - query = query, - chainsById = chainsById, - tokenSymbol = { it.token.configuration.symbol.value }, - relevantToChains = { asset, chainIds -> asset.token.configuration.chainId in chainIds } - ) - } -} - -private fun AssetSearchInteractor.searchAssetsByNetworksInternalFlow( - queryFlow: Flow, - externalBalancesFlow: Flow>, - assetGroupComparator: Comparator = getAssetGroupBaseComparator(), - assetsComparator: Comparator = getAssetBaseComparator(), - filter: AssetSearchFilter?, -): Flow>> { - val filterFlow = flowOf(filter) - - return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, assetGroupComparator, assetsComparator, filterFlow) -} - -private fun AssetSearchInteractor.searchAssetsByTokensInternalFlow( - queryFlow: Flow, - externalBalancesFlow: Flow>, - assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), - assetsComparator: Comparator = getTokenAssetBaseComparator(), - filter: AssetSearchFilter?, -): Flow>> { - val filterFlow = flowOf(filter) - - return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, assetGroupComparator, assetsComparator, filterFlow) + ): Flow } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchUseCase.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchUseCase.kt new file mode 100644 index 0000000000..677231e93f --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchUseCase.kt @@ -0,0 +1,58 @@ +package io.novafoundation.nova.feature_assets.domain.assets.search + +import io.novafoundation.nova.common.utils.flowOfAll +import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository +import io.novafoundation.nova.feature_assets.domain.common.searchTokens +import io.novafoundation.nova.feature_swap_api.domain.swap.SwapService +import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletRepository +import io.novafoundation.nova.feature_wallet_api.domain.model.Asset +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry +import io.novafoundation.nova.runtime.multiNetwork.ChainsById +import io.novafoundation.nova.runtime.multiNetwork.asset +import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flatMapLatest + +class AssetSearchUseCase( + private val walletRepository: WalletRepository, + private val accountRepository: AccountRepository, + private val chainRegistry: ChainRegistry, + private val swapService: SwapService +) { + + fun filteredAssetFlow(filterFlow: Flow): Flow> { + val assetsFlow = accountRepository.selectedMetaAccountFlow() + .flatMapLatest { walletRepository.syncedAssetsFlow(it.id) } + + return combine(assetsFlow, filterFlow) { assets, filter -> + if (filter == null) { + assets + } else { + assets.filter { filter(it) } + } + } + } + + fun filterAssetsByQuery(query: String, assets: List, chainsById: ChainsById): List { + return assets.searchTokens( + query = query, + chainsById = chainsById, + tokenSymbol = { it.token.configuration.symbol.value }, + relevantToChains = { asset, chainIds -> asset.token.configuration.chainId in chainIds } + ) + } + + fun getAvailableSwapAssets(asset: FullChainAssetId?, coroutineScope: CoroutineScope): Flow> { + return flowOfAll { + val chainAsset = asset?.let { chainRegistry.asset(it) } + + if (chainAsset == null) { + swapService.assetsAvailableForSwap(coroutineScope) + } else { + swapService.availableSwapDirectionsFor(chainAsset, coroutineScope) + } + } + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetViewModeAssetSearchInteractorFactory.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetViewModeAssetSearchInteractorFactory.kt new file mode 100644 index 0000000000..1617517d26 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetViewModeAssetSearchInteractorFactory.kt @@ -0,0 +1,26 @@ +package io.novafoundation.nova.feature_assets.domain.assets.search + +import io.novafoundation.nova.common.data.model.AssetViewMode +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry + +class AssetViewModeAssetSearchInteractorFactory( + private val assetViewModeRepository: AssetsViewModeRepository, + private val assetSearchUseCase: AssetSearchUseCase, + private val chainRegistry: ChainRegistry +) : AssetSearchInteractorFactory { + + override fun createByAssetViewMode(): AssetSearchInteractor { + return when (assetViewModeRepository.getAssetViewMode()) { + AssetViewMode.TOKENS -> ByTokensAssetSearchInteractor( + assetSearchUseCase, + chainRegistry + ) + + AssetViewMode.NETWORKS -> ByNetworkAssetSearchInteractor( + assetSearchUseCase, + chainRegistry + ) + } + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByNetworkAssetSearchInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByNetworkAssetSearchInteractor.kt new file mode 100644 index 0000000000..3815982594 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByNetworkAssetSearchInteractor.kt @@ -0,0 +1,116 @@ +package io.novafoundation.nova.feature_assets.domain.assets.search + +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup +import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.getAssetBaseComparator +import io.novafoundation.nova.feature_assets.domain.common.getAssetGroupBaseComparator +import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByNetwork +import io.novafoundation.nova.feature_wallet_api.domain.model.Asset +import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance +import io.novafoundation.nova.feature_wallet_api.domain.model.aggregatedBalanceByAsset +import io.novafoundation.nova.runtime.ext.fullId +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry +import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId +import io.novafoundation.nova.runtime.multiNetwork.enabledChainById +import io.novasama.substrate_sdk_android.hash.isPositive +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map + +class ByNetworkAssetSearchInteractor( + private val assetSearchUseCase: AssetSearchUseCase, + private val chainRegistry: ChainRegistry +) : AssetSearchInteractor { + + override fun buyAssetSearch( + queryFlow: Flow, + externalBalancesFlow: Flow>, + ): Flow { + val filter = { asset: Asset -> asset.token.configuration.buyProviders.isNotEmpty() } + + return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = filter) + } + + override fun sendAssetSearch( + queryFlow: Flow, + externalBalancesFlow: Flow>, + ): Flow { + val filter = { asset: Asset -> asset.transferableInPlanks.isPositive() } + + return searchAssetsByNetworksInternalFlow( + queryFlow, + externalBalancesFlow, + assetGroupComparator = getAssetGroupBaseComparator { it.groupTransferableBalanceFiat }, + assetsComparator = getAssetBaseComparator { it.balanceWithOffchain.transferable.fiat }, + filter = filter + ) + } + + override fun searchSwapAssetsFlow( + forAsset: FullChainAssetId?, + queryFlow: Flow, + externalBalancesFlow: Flow>, + coroutineScope: CoroutineScope + ): Flow { + val filterFlow = assetSearchUseCase.getAvailableSwapAssets(forAsset, coroutineScope).map { availableAssetsForSwap -> + val filter: AssetSearchFilter = { asset -> + val chainAsset = asset.token.configuration + + chainAsset.fullId in availableAssetsForSwap + } + + filter + } + + return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filterFlow = filterFlow) + } + + override fun searchReceiveAssetsFlow( + queryFlow: Flow, + externalBalancesFlow: Flow>, + ): Flow { + return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = null) + } + + override fun searchAssetsFlow( + queryFlow: Flow, + externalBalancesFlow: Flow>, + ): Flow { + return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = null) + } + + private fun ByNetworkAssetSearchInteractor.searchAssetsByNetworksInternalFlow( + queryFlow: Flow, + externalBalancesFlow: Flow>, + assetGroupComparator: Comparator = getAssetGroupBaseComparator(), + assetsComparator: Comparator = getAssetBaseComparator(), + filter: AssetSearchFilter?, + ): Flow { + val filterFlow = flowOf(filter) + + return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, assetGroupComparator, assetsComparator, filterFlow) + } + + private fun searchAssetsByNetworksInternalFlow( + queryFlow: Flow, + externalBalancesFlow: Flow>, + assetGroupComparator: Comparator = getAssetGroupBaseComparator(), + assetsComparator: Comparator = getAssetBaseComparator(), + filterFlow: Flow, + ): Flow { + val assetsFlow = assetSearchUseCase.filteredAssetFlow(filterFlow) + + val aggregatedExternalBalances = externalBalancesFlow.map { it.aggregatedBalanceByAsset() } + + return combine(assetsFlow, aggregatedExternalBalances, queryFlow) { assets, externalBalances, query -> + val chainsById = chainRegistry.enabledChainById() + val filtered = assetSearchUseCase.filterAssetsByQuery(query, assets, chainsById) + + val assetGroups = groupAndSortAssetsByNetwork(filtered, externalBalances, chainsById, assetGroupComparator, assetsComparator) + AssetFlowSearchResult.ByNetworks(assetGroups) + } + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt new file mode 100644 index 0000000000..24bfd9f9ee --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt @@ -0,0 +1,117 @@ +package io.novafoundation.nova.feature_assets.domain.assets.search + +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup +import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetBaseComparator +import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetGroupBaseComparator +import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByToken +import io.novafoundation.nova.feature_wallet_api.domain.model.Asset +import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance +import io.novafoundation.nova.feature_wallet_api.domain.model.aggregatedBalanceByAsset +import io.novafoundation.nova.runtime.ext.fullId +import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry +import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId +import io.novafoundation.nova.runtime.multiNetwork.enabledChainById +import io.novasama.substrate_sdk_android.hash.isPositive +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map + +class ByTokensAssetSearchInteractor( + private val assetSearchUseCase: AssetSearchUseCase, + private val chainRegistry: ChainRegistry +) : AssetSearchInteractor { + + override fun buyAssetSearch( + queryFlow: Flow, + externalBalancesFlow: Flow>, + ): Flow { + val filter = { asset: Asset -> asset.token.configuration.buyProviders.isNotEmpty() } + + return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = filter) + } + + override fun sendAssetSearch( + queryFlow: Flow, + externalBalancesFlow: Flow>, + ): Flow { + val filter = { asset: Asset -> asset.transferableInPlanks.isPositive() } + + return searchAssetsByTokensInternalFlow( + queryFlow, + externalBalancesFlow, + assetGroupComparator = getTokenAssetGroupBaseComparator { it.groupBalance.transferable.fiat }, + assetsComparator = getTokenAssetBaseComparator { it.balanceWithOffChain.transferable.fiat }, + filter = filter + ) + } + + override fun searchSwapAssetsFlow( + forAsset: FullChainAssetId?, + queryFlow: Flow, + externalBalancesFlow: Flow>, + coroutineScope: CoroutineScope + ): Flow { + val filterFlow = assetSearchUseCase.getAvailableSwapAssets(forAsset, coroutineScope).map { availableAssetsForSwap -> + val filter: AssetSearchFilter = { asset -> + val chainAsset = asset.token.configuration + + chainAsset.fullId in availableAssetsForSwap + } + + filter + } + + return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filterFlow = filterFlow) + } + + override fun searchReceiveAssetsFlow( + queryFlow: Flow, + externalBalancesFlow: Flow>, + ): Flow { + return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = null) + } + + override fun searchAssetsFlow( + queryFlow: Flow, + externalBalancesFlow: Flow>, + ): Flow { + return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = null) + } + + private fun searchAssetsByTokensInternalFlow( + queryFlow: Flow, + externalBalancesFlow: Flow>, + assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), + assetsComparator: Comparator = getTokenAssetBaseComparator(), + filter: AssetSearchFilter?, + ): Flow { + val filterFlow = flowOf(filter) + + return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, assetGroupComparator, assetsComparator, filterFlow) + } + + private fun searchAssetsByTokensInternalFlow( + queryFlow: Flow, + externalBalancesFlow: Flow>, + assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), + assetsComparator: Comparator = getTokenAssetBaseComparator(), + filterFlow: Flow, + ): Flow { + val assetsFlow = assetSearchUseCase.filteredAssetFlow(filterFlow) + + val aggregatedExternalBalances = externalBalancesFlow.map { it.aggregatedBalanceByAsset() } + + return combine(assetsFlow, aggregatedExternalBalances, queryFlow) { assets, externalBalances, query -> + val chainsById = chainRegistry.enabledChainById() + val filtered = assetSearchUseCase.filterAssetsByQuery(query, assets, chainsById) + + val assetGroups = groupAndSortAssetsByToken(filtered, externalBalances, chainsById, assetGroupComparator, assetsComparator) + + AssetFlowSearchResult.ByTokens(assetGroups) + } + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt index ce02ef17e3..688385d856 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt @@ -5,6 +5,8 @@ import io.novafoundation.nova.common.utils.filterList import io.novafoundation.nova.common.utils.filterSet import io.novafoundation.nova.common.utils.flowOfAll import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchFilter +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchUseCase import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetBaseComparator @@ -15,26 +17,24 @@ import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletReposit import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance import io.novafoundation.nova.feature_wallet_api.domain.model.aggregatedBalanceByAsset +import io.novafoundation.nova.runtime.ext.fullId +import io.novafoundation.nova.runtime.ext.normalize import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry -import io.novafoundation.nova.runtime.multiNetwork.asset import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId import io.novafoundation.nova.runtime.multiNetwork.enabledChainById +import io.novafoundation.nova.runtime.multiNetwork.enabledChains import io.novasama.substrate_sdk_android.hash.isPositive import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map -private typealias AssetFilter = suspend (Asset) -> Boolean - class AssetNetworksInteractor( - private val walletRepository: WalletRepository, - private val accountRepository: AccountRepository, private val chainRegistry: ChainRegistry, - private val swapService: SwapService + private val swapService: SwapService, + private val assetSearchUseCase: AssetSearchUseCase ) { fun buyAssetFlow( @@ -63,9 +63,12 @@ class AssetNetworksInteractor( fun swapAssetsFlow( tokenSymbol: TokenSymbol, - externalBalancesFlow: Flow> + externalBalancesFlow: Flow>, + coroutineScope: CoroutineScope ): Flow> { - return searchAssetsByTokenSymbolInternalFlow(tokenSymbol, externalBalancesFlow, filter = null) + val filterFlow = getSwapAssetsFilter(tokenSymbol, coroutineScope) + + return searchAssetsByTokenSymbolInternalFlow(tokenSymbol, externalBalancesFlow, filterFlow = filterFlow) } fun receiveAssetFlow( @@ -80,10 +83,10 @@ class AssetNetworksInteractor( externalBalancesFlow: Flow>, assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), assetsComparator: Comparator = getTokenAssetBaseComparator(), - filterFlow: Flow, + filterFlow: Flow, ): Flow> { - val assetsFlow = filteredAssetFlow(filterFlow) - .filterList { it.token.configuration.symbol == tokenSymbol } + val assetsFlow = assetSearchUseCase.filteredAssetFlow(filterFlow) + .filterList { it.token.configuration.symbol.normalize() == tokenSymbol } val aggregatedExternalBalances = externalBalancesFlow.map { it.aggregatedBalanceByAsset() } @@ -95,29 +98,27 @@ class AssetNetworksInteractor( } } - private fun filteredAssetFlow(filterFlow: Flow): Flow> { - val assetsFlow = accountRepository.selectedMetaAccountFlow() - .flatMapLatest { walletRepository.syncedAssetsFlow(it.id) } + private fun getSwapAssetsFilter(tokenSymbol: TokenSymbol, coroutineScope: CoroutineScope): Flow { + return getAvailableSwapAssets(tokenSymbol, coroutineScope) + .map { availableAssetsForSwap -> + val assetFilter: suspend (Asset) -> Boolean = { asset: Asset -> + asset.token.configuration.fullId in availableAssetsForSwap + } - return combine(assetsFlow, filterFlow) { assets, filter -> - if (filter == null) { - assets - } else { - assets.filter { filter(it) } + assetFilter } - } } private fun getAvailableSwapAssets(tokenSymbol: TokenSymbol, coroutineScope: CoroutineScope): Flow> { return flowOfAll { - val chains = chainRegistry.enabledChainById() - .filter { (_, chain) -> - // Take only chains that have target asset - chain.assets.any { it.symbol == tokenSymbol } + val assetsSupportedTokenSymbol = chainRegistry.enabledChains() + .flatMap { chain -> + chain.assets.filter { it.symbol.normalize() == tokenSymbol } + .map { it.fullId } } swapService.assetsAvailableForSwap(coroutineScope) - .filterSet { it.chainId in chains.keys } + .filterSet { fullAssetId -> fullAssetId in assetsSupportedTokenSymbol } } } } @@ -127,7 +128,7 @@ private fun AssetNetworksInteractor.searchAssetsByTokenSymbolInternalFlow( externalBalancesFlow: Flow>, assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), assetsComparator: Comparator = getTokenAssetBaseComparator(), - filter: AssetFilter?, + filter: AssetSearchFilter?, ): Flow> { val filterFlow = flowOf(filter) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index 39438a2fec..b621eefd4c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -17,7 +17,7 @@ import io.novafoundation.nova.feature_currency_api.presentation.formatters.forma import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel fun GroupedList.mapGroupedAssetsToUi( - assetFilter: (groupId: String, List) -> List, + assetFilter: (groupId: String, List) -> List = { _, assets -> assets }, groupBalance: (TokenAssetGroup) -> PricedAmount = { it.groupBalance.total }, balance: (AssetBalance) -> PricedAmount = AssetBalance::total, ): List { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt index 6c6fb62850..6642190511 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt @@ -3,7 +3,8 @@ package io.novafoundation.nova.feature_assets.presentation.balance.search import io.novafoundation.nova.common.base.BaseViewModel import io.novafoundation.nova.common.utils.inBackground import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi @@ -15,11 +16,13 @@ import kotlinx.coroutines.flow.distinctUntilChanged class AssetSearchViewModel( private val router: AssetsRouter, - interactor: AssetSearchInteractor, + interactorFactory: AssetSearchInteractorFactory, currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor, ) : BaseViewModel() { + val interactor = interactorFactory.createByAssetViewMode() + val query = MutableStateFlow("") private val selectedCurrency = currencyInteractor.observeSelectCurrency() @@ -32,7 +35,10 @@ class AssetSearchViewModel( interactor.searchAssetsFlow(query, externalBalances), selectedCurrency, ) { assets, currency -> - assets.mapGroupedAssetsToUi(currency) + when (assets) { + is AssetFlowSearchResult.ByNetworks -> assets.assets.mapGroupedAssetsToUi(currency) + is AssetFlowSearchResult.ByTokens -> assets.tokens.mapGroupedAssetsToUi() + } } .distinctUntilChanged() .shareInBackground() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt index c85f6e372f..29a57940bd 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt @@ -9,7 +9,7 @@ import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.search.AssetSearchViewModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor @@ -27,13 +27,13 @@ class AssetSearchModule { @ViewModelKey(AssetSearchViewModel::class) fun provideViewModel( router: AssetsRouter, - interactor: AssetSearchInteractor, + interactorFactory: AssetSearchInteractorFactory, currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor ): ViewModel { return AssetSearchViewModel( router = router, - interactor = interactor, + interactorFactory = interactorFactory, currencyInteractor = currencyInteractor, externalBalancesInteractor = externalBalancesInteractor ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt index df2c280bc6..14569eee7c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt @@ -4,7 +4,7 @@ import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi @@ -16,7 +16,7 @@ import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import kotlinx.coroutines.flow.Flow class AssetBuyFlowViewModel( - interactor: AssetSearchInteractor, + interactorFactory: AssetSearchInteractorFactory, router: AssetsRouter, externalBalancesInteractor: ExternalBalancesInteractor, currencyInteractor: CurrencyInteractor, @@ -25,7 +25,7 @@ class AssetBuyFlowViewModel( buyMixinFactory: BuyMixin.Factory, resourceManager: ResourceManager, ) : AssetFlowViewModel( - interactor, + interactorFactory, router, currencyInteractor, controllableAssetCheck, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt index d0c63c162e..8519fe30fb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt @@ -11,7 +11,7 @@ import io.novafoundation.nova.common.di.viewmodel.ViewModelModule import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowViewModel @@ -30,7 +30,7 @@ class AssetBuyFlowModule { @IntoMap @ViewModelKey(AssetBuyFlowViewModel::class) fun provideViewModel( - interactor: AssetSearchInteractor, + interactorFactory: AssetSearchInteractorFactory, router: AssetsRouter, externalBalancesInteractor: ExternalBalancesInteractor, currencyInteractor: CurrencyInteractor, @@ -40,7 +40,7 @@ class AssetBuyFlowModule { resourceManager: ResourceManager ): ViewModel { return AssetBuyFlowViewModel( - interactor = interactor, + interactorFactory = interactorFactory, router = router, externalBalancesInteractor = externalBalancesInteractor, currencyInteractor = currencyInteractor, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt index df0164065a..e548707e61 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowFragment.kt @@ -1,17 +1,15 @@ package io.novafoundation.nova.feature_assets.presentation.buy.flow.network import io.novafoundation.nova.common.di.FeatureUtils -import io.novafoundation.nova.common.utils.FragmentPayloadHolder +import io.novafoundation.nova.common.utils.payload import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment -import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixinUi import javax.inject.Inject class NetworkBuyFlowFragment : - NetworkFlowFragment(), - FragmentPayloadHolder { + NetworkFlowFragment() { @Inject lateinit var buyMixin: BuyMixinUi @@ -19,7 +17,7 @@ class NetworkBuyFlowFragment : override fun inject() { FeatureUtils.getFeature(this, AssetsFeatureApi::class.java) .networkBuyFlowComponent() - .create(this, payload) + .create(this, payload()) .inject(this) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt index a8314ccb47..f9cb172e99 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/network/NetworkBuyFlowViewModel.kt @@ -51,7 +51,7 @@ class NetworkBuyFlowViewModel( } override fun networkClicked(network: NetworkFlowRvItem) { - validate(network) { + validateControllsAsset(network) { launch { val chainAsset = chainRegistry.asset(network.chainId, network.assetId) buyMixin.buyClicked(chainAsset) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index c4e9976e83..364d2d9a2a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -10,7 +10,7 @@ import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult import io.novafoundation.nova.feature_assets.domain.assets.models.groupList -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance @@ -33,15 +33,17 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch abstract class AssetFlowViewModel( - protected val interactor: AssetSearchInteractor, + interactorFactory: AssetSearchInteractorFactory, protected val router: AssetsRouter, protected val currencyInteractor: CurrencyInteractor, private val controllableAssetCheck: ControllableAssetCheckMixin, - internal val accountUseCase: SelectedAccountUseCase, + protected val accountUseCase: SelectedAccountUseCase, externalBalancesInteractor: ExternalBalancesInteractor, - internal val resourceManager: ResourceManager, + protected val resourceManager: ResourceManager, ) : BaseViewModel() { + protected val interactor = interactorFactory.createByAssetViewMode() + val acknowledgeLedgerWarning = controllableAssetCheck.acknowledgeLedgerWarning val query = MutableStateFlow("") @@ -53,6 +55,7 @@ abstract class AssetFlowViewModel( protected val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() private val searchAssetsFlow = flowOfAll { searchAssetsFlow() } + .shareInBackground() val searchResults = combine( searchAssetsFlow, // lazy use searchAssetsFlow to let subclasses initialize self diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt index 75dbdeb99b..0a09caeec7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/network/NetworkFlowViewModel.kt @@ -23,11 +23,11 @@ abstract class NetworkFlowViewModel( protected val interactor: AssetNetworksInteractor, protected val router: AssetsRouter, private val controllableAssetCheck: ControllableAssetCheckMixin, - internal val accountUseCase: SelectedAccountUseCase, + protected val accountUseCase: SelectedAccountUseCase, externalBalancesInteractor: ExternalBalancesInteractor, - internal val resourceManager: ResourceManager, + protected val resourceManager: ResourceManager, private val networkFlowPayload: NetworkFlowPayload, - internal val chainRegistry: ChainRegistry + protected val chainRegistry: ChainRegistry ) : BaseViewModel() { val acknowledgeLedgerWarning = controllableAssetCheck.acknowledgeLedgerWarning @@ -50,7 +50,7 @@ abstract class NetworkFlowViewModel( router.back() } - internal fun validate(networkFlowRvItem: NetworkFlowRvItem, onAccept: () -> Unit) { + internal fun validateControllsAsset(networkFlowRvItem: NetworkFlowRvItem, onAccept: () -> Unit) { launch { val metaAccount = accountUseCase.getSelectedMetaAccount() val chainAsset = chainRegistry.asset(networkFlowRvItem.chainId, networkFlowRvItem.assetId) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt index 309a023e52..2678ba2a6c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt @@ -4,7 +4,7 @@ import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin @@ -16,7 +16,7 @@ import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import kotlinx.coroutines.flow.Flow class AssetReceiveFlowViewModel( - interactor: AssetSearchInteractor, + interactorFactory: AssetSearchInteractorFactory, router: AssetsRouter, currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor, @@ -24,7 +24,7 @@ class AssetReceiveFlowViewModel( accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, ) : AssetFlowViewModel( - interactor, + interactorFactory, router, currencyInteractor, controllableAssetCheck, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt index b918a582c8..4b74994f4b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt @@ -11,7 +11,7 @@ import io.novafoundation.nova.common.di.viewmodel.ViewModelModule import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.receive.flow.asset.AssetReceiveFlowViewModel @@ -29,7 +29,7 @@ class AssetReceiveFlowModule { @IntoMap @ViewModelKey(AssetReceiveFlowViewModel::class) fun provideViewModel( - interactor: AssetSearchInteractor, + interactorFactory: AssetSearchInteractorFactory, router: AssetsRouter, currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor, @@ -38,7 +38,7 @@ class AssetReceiveFlowModule { resourceManager: ResourceManager ): ViewModel { return AssetReceiveFlowViewModel( - interactor = interactor, + interactorFactory = interactorFactory, router = router, currencyInteractor = currencyInteractor, externalBalancesInteractor = externalBalancesInteractor, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt index 75aeabdadf..a936e0abf0 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowFragment.kt @@ -1,20 +1,18 @@ package io.novafoundation.nova.feature_assets.presentation.receive.flow.network import io.novafoundation.nova.common.di.FeatureUtils -import io.novafoundation.nova.common.utils.FragmentPayloadHolder +import io.novafoundation.nova.common.utils.payload import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment -import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload class NetworkReceiveFlowFragment : - NetworkFlowFragment(), - FragmentPayloadHolder { + NetworkFlowFragment() { override fun inject() { FeatureUtils.getFeature(this, AssetsFeatureApi::class.java) .networkReceiveFlowComponent() - .create(this, payload) + .create(this, payload()) .inject(this) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt index 535dbde27a..b8802c081f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/network/NetworkReceiveFlowViewModel.kt @@ -46,7 +46,7 @@ class NetworkReceiveFlowViewModel( } override fun networkClicked(network: NetworkFlowRvItem) { - validate(network) { + validateControllsAsset(network) { router.openReceive(AssetPayload(network.chainId, network.assetId)) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt index 9401f1c763..935d9f6179 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt @@ -6,7 +6,7 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAcco import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance @@ -28,7 +28,7 @@ import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import kotlinx.coroutines.flow.Flow class AssetSendFlowViewModel( - interactor: AssetSearchInteractor, + interactorFactory: AssetSearchInteractorFactory, router: AssetsRouter, currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor, @@ -36,7 +36,7 @@ class AssetSendFlowViewModel( accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, ) : AssetFlowViewModel( - interactor, + interactorFactory, router, currencyInteractor, controllableAssetCheck, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt index 7fdf4bb8f1..5790a6cf5c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt @@ -11,7 +11,7 @@ import io.novafoundation.nova.common.di.viewmodel.ViewModelModule import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.send.flow.asset.AssetSendFlowViewModel @@ -29,7 +29,7 @@ class AssetSendFlowModule { @IntoMap @ViewModelKey(AssetSendFlowViewModel::class) fun provideViewModel( - interactor: AssetSearchInteractor, + interactorFactory: AssetSearchInteractorFactory, router: AssetsRouter, currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor, @@ -38,7 +38,7 @@ class AssetSendFlowModule { resourceManager: ResourceManager ): ViewModel { return AssetSendFlowViewModel( - interactor = interactor, + interactorFactory = interactorFactory, router = router, currencyInteractor = currencyInteractor, externalBalancesInteractor = externalBalancesInteractor, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt index 5f393d3e10..cb2b8f32ba 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/network/NetworkSendFlowFragment.kt @@ -1,20 +1,18 @@ package io.novafoundation.nova.feature_assets.presentation.send.flow.network import io.novafoundation.nova.common.di.FeatureUtils -import io.novafoundation.nova.common.utils.FragmentPayloadHolder +import io.novafoundation.nova.common.utils.payload import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment -import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload class NetworkSendFlowFragment : - NetworkFlowFragment(), - FragmentPayloadHolder { + NetworkFlowFragment() { override fun inject() { FeatureUtils.getFeature(this, AssetsFeatureApi::class.java) .networkSendFlowComponent() - .create(this, payload) + .create(this, payload()) .inject(this) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index 63db3e3d28..0197394adb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.swap.asset +import android.util.Log import androidx.annotation.StringRes import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.resources.ResourceManager @@ -8,7 +9,7 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAcco import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance @@ -33,7 +34,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch class AssetSwapFlowViewModel( - interactor: AssetSearchInteractor, + interactorFactory: AssetSearchInteractorFactory, router: AssetsRouter, currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor, @@ -44,7 +45,7 @@ class AssetSwapFlowViewModel( private val swapFlowExecutor: SwapFlowExecutor, private val swapPayload: SwapFlowPayload ) : AssetFlowViewModel( - interactor, + interactorFactory, router, currencyInteractor, controllableAssetCheck, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt index 3ee24a13bf..b40fbd2b7f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt @@ -11,7 +11,7 @@ import io.novafoundation.nova.common.di.viewmodel.ViewModelModule import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor +import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.swap.asset.AssetSwapFlowViewModel @@ -32,7 +32,7 @@ class AssetSwapFlowModule { @IntoMap @ViewModelKey(AssetSwapFlowViewModel::class) fun provideViewModel( - interactor: AssetSearchInteractor, + interactorFactory: AssetSearchInteractorFactory, router: AssetsRouter, currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor, @@ -44,7 +44,7 @@ class AssetSwapFlowModule { swapAvailabilityInteractor: SwapAvailabilityInteractor ): ViewModel { return AssetSwapFlowViewModel( - interactor = interactor, + interactorFactory = interactorFactory, router = router, currencyInteractor = currencyInteractor, externalBalancesInteractor = externalBalancesInteractor, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt index 362d893a67..1cf3b4ac6d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowFragment.kt @@ -2,22 +2,21 @@ package io.novafoundation.nova.feature_assets.presentation.swap.network import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.FragmentPayloadCreator -import io.novafoundation.nova.common.utils.FragmentPayloadHolder import io.novafoundation.nova.common.utils.PayloadCreator +import io.novafoundation.nova.common.utils.payload import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowFragment class NetworkSwapFlowFragment : - NetworkFlowFragment(), - FragmentPayloadHolder { + NetworkFlowFragment() { companion object : PayloadCreator by FragmentPayloadCreator() override fun inject() { FeatureUtils.getFeature(this, AssetsFeatureApi::class.java) .networkSwapFlowComponent() - .create(this, payload) + .create(this, payload()) .inject(this) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt index 8771188d68..208687d1d3 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/network/NetworkSwapFlowViewModel.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.swap.network +import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.TokenSymbol import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -45,7 +46,7 @@ class NetworkSwapFlowViewModel( } override fun assetsFlow(tokenSymbol: TokenSymbol): Flow> { - return interactor.swapAssetsFlow(tokenSymbol, externalBalancesFlow) + return interactor.swapAssetsFlow(tokenSymbol, externalBalancesFlow, viewModelScope) } override fun networkClicked(network: NetworkFlowRvItem) { From 19b1b6dc44a60ed4c7ca69cc5fc9bb43f12f46cb Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 11:30:16 +0100 Subject: [PATCH 31/78] Search assets screen --- .../feature_assets/di/AssetsFeatureModule.kt | 14 ++++ .../assets/models/AssetFlowSearchResult.kt | 21 ----- .../assets/models/AssetsByViewModeResult.kt | 29 +++++++ .../assets/search/AssetSearchInteractor.kt | 12 +-- .../search/ByNetworkAssetSearchInteractor.kt | 18 ++-- .../search/ByTokensAssetSearchInteractor.kt | 18 ++-- .../AssetExpandableAssetDecorationSettings.kt | 6 ++ .../balance/common/AssetListMixin.kt | 68 ++++----------- .../balance/common/ExpandableAssetsMixin.kt | 84 +++++++++++++++++++ .../balance/list/BalanceListFragment.kt | 5 +- .../balance/list/BalanceListViewModel.kt | 4 +- .../balance/list/di/BalanceListModule.kt | 11 ++- .../balance/search/AssetSearchFragment.kt | 27 ++++-- .../balance/search/AssetSearchViewModel.kt | 29 ++----- .../balance/search/di/AssetSearchModule.kt | 10 +-- .../buy/flow/asset/AssetBuyFlowViewModel.kt | 4 +- .../flow/asset/AssetFlowViewModel.kt | 10 +-- .../flow/asset/AssetReceiveFlowViewModel.kt | 4 +- .../send/flow/asset/AssetSendFlowViewModel.kt | 4 +- .../swap/asset/AssetSwapFlowViewModel.kt | 5 +- 20 files changed, 227 insertions(+), 156 deletions(-) delete mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetsByViewModeResult.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetExpandableAssetDecorationSettings.kt create mode 100644 feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt index ac85f5d176..f9d2d0ab5a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt @@ -30,9 +30,11 @@ import io.novafoundation.nova.feature_assets.domain.assets.search.AssetViewModeA import io.novafoundation.nova.feature_assets.domain.networks.AssetNetworksInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin +import io.novafoundation.nova.feature_assets.presentation.balance.common.ExpandableAssetsMixinFactory import io.novafoundation.nova.feature_assets.presentation.swap.executor.InitialSwapFlowExecutor import io.novafoundation.nova.feature_assets.presentation.swap.executor.SwapFlowExecutorFactory import io.novafoundation.nova.feature_assets.presentation.transaction.filter.HistoryFiltersProviderFactory +import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.interfaces.CurrencyRepository import io.novafoundation.nova.feature_nft_api.data.repository.NftRepository import io.novafoundation.nova.feature_staking_api.data.network.blockhain.updaters.PooledBalanceUpdaterFactory @@ -182,4 +184,16 @@ class AssetsFeatureModule { ): SwapFlowExecutorFactory { return SwapFlowExecutorFactory(initialSwapFlowExecutor, assetsRouter, swapSettingsStateProvider) } + + @Provides + @FeatureScope + fun provideExpandableAssetsMixinFactory( + currencyInteractor: CurrencyInteractor, + assetsViewModeRepository: AssetsViewModeRepository + ): ExpandableAssetsMixinFactory { + return ExpandableAssetsMixinFactory( + currencyInteractor, + assetsViewModeRepository + ) + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt deleted file mode 100644 index e0067b0813..0000000000 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetFlowSearchResult.kt +++ /dev/null @@ -1,21 +0,0 @@ -package io.novafoundation.nova.feature_assets.domain.assets.models - -import io.novafoundation.nova.common.utils.MultiMapList -import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork -import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance -import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup -import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup - -sealed interface AssetFlowSearchResult { - - class ByNetworks(val assets: MultiMapList) : AssetFlowSearchResult - - class ByTokens(val tokens: MultiMapList) : AssetFlowSearchResult -} - -fun AssetFlowSearchResult.groupList(): List { - return when (this) { - is AssetFlowSearchResult.ByNetworks -> assets.keys.toList() - is AssetFlowSearchResult.ByTokens -> tokens.keys.toList() - } -} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetsByViewModeResult.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetsByViewModeResult.kt new file mode 100644 index 0000000000..a51611a4a8 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/models/AssetsByViewModeResult.kt @@ -0,0 +1,29 @@ +package io.novafoundation.nova.feature_assets.domain.assets.models + +import io.novafoundation.nova.common.utils.MultiMapList +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup + +sealed interface AssetsByViewModeResult { + + class ByNetworks(val assets: MultiMapList) : AssetsByViewModeResult + + class ByTokens(val tokens: MultiMapList) : AssetsByViewModeResult +} + +fun AssetsByViewModeResult.groupList(): List { + return when (this) { + is AssetsByViewModeResult.ByNetworks -> assets.keys.toList() + is AssetsByViewModeResult.ByTokens -> tokens.keys.toList() + } +} + +fun MultiMapList.byNetworks(): AssetsByViewModeResult { + return AssetsByViewModeResult.ByNetworks(this) +} + +fun MultiMapList.byTokens(): AssetsByViewModeResult { + return AssetsByViewModeResult.ByTokens(this) +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt index 4d39ae339e..3c4ec20485 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/AssetSearchInteractor.kt @@ -1,6 +1,6 @@ package io.novafoundation.nova.feature_assets.domain.assets.search -import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId @@ -19,27 +19,27 @@ interface AssetSearchInteractor { fun buyAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow + ): Flow fun sendAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow + ): Flow fun searchSwapAssetsFlow( forAsset: FullChainAssetId?, queryFlow: Flow, externalBalancesFlow: Flow>, coroutineScope: CoroutineScope - ): Flow + ): Flow fun searchReceiveAssetsFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow + ): Flow fun searchAssetsFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow + ): Flow } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByNetworkAssetSearchInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByNetworkAssetSearchInteractor.kt index 3815982594..88341f2cff 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByNetworkAssetSearchInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByNetworkAssetSearchInteractor.kt @@ -1,6 +1,6 @@ package io.novafoundation.nova.feature_assets.domain.assets.search -import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance import io.novafoundation.nova.feature_assets.domain.common.getAssetBaseComparator @@ -28,7 +28,7 @@ class ByNetworkAssetSearchInteractor( override fun buyAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow { + ): Flow { val filter = { asset: Asset -> asset.token.configuration.buyProviders.isNotEmpty() } return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = filter) @@ -37,7 +37,7 @@ class ByNetworkAssetSearchInteractor( override fun sendAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow { + ): Flow { val filter = { asset: Asset -> asset.transferableInPlanks.isPositive() } return searchAssetsByNetworksInternalFlow( @@ -54,7 +54,7 @@ class ByNetworkAssetSearchInteractor( queryFlow: Flow, externalBalancesFlow: Flow>, coroutineScope: CoroutineScope - ): Flow { + ): Flow { val filterFlow = assetSearchUseCase.getAvailableSwapAssets(forAsset, coroutineScope).map { availableAssetsForSwap -> val filter: AssetSearchFilter = { asset -> val chainAsset = asset.token.configuration @@ -71,14 +71,14 @@ class ByNetworkAssetSearchInteractor( override fun searchReceiveAssetsFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow { + ): Flow { return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = null) } override fun searchAssetsFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow { + ): Flow { return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, filter = null) } @@ -88,7 +88,7 @@ class ByNetworkAssetSearchInteractor( assetGroupComparator: Comparator = getAssetGroupBaseComparator(), assetsComparator: Comparator = getAssetBaseComparator(), filter: AssetSearchFilter?, - ): Flow { + ): Flow { val filterFlow = flowOf(filter) return searchAssetsByNetworksInternalFlow(queryFlow, externalBalancesFlow, assetGroupComparator, assetsComparator, filterFlow) @@ -100,7 +100,7 @@ class ByNetworkAssetSearchInteractor( assetGroupComparator: Comparator = getAssetGroupBaseComparator(), assetsComparator: Comparator = getAssetBaseComparator(), filterFlow: Flow, - ): Flow { + ): Flow { val assetsFlow = assetSearchUseCase.filteredAssetFlow(filterFlow) val aggregatedExternalBalances = externalBalancesFlow.map { it.aggregatedBalanceByAsset() } @@ -110,7 +110,7 @@ class ByNetworkAssetSearchInteractor( val filtered = assetSearchUseCase.filterAssetsByQuery(query, assets, chainsById) val assetGroups = groupAndSortAssetsByNetwork(filtered, externalBalances, chainsById, assetGroupComparator, assetsComparator) - AssetFlowSearchResult.ByNetworks(assetGroups) + AssetsByViewModeResult.ByNetworks(assetGroups) } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt index 24bfd9f9ee..2410f2e2df 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt @@ -1,6 +1,6 @@ package io.novafoundation.nova.feature_assets.domain.assets.search -import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetBaseComparator @@ -28,7 +28,7 @@ class ByTokensAssetSearchInteractor( override fun buyAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow { + ): Flow { val filter = { asset: Asset -> asset.token.configuration.buyProviders.isNotEmpty() } return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = filter) @@ -37,7 +37,7 @@ class ByTokensAssetSearchInteractor( override fun sendAssetSearch( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow { + ): Flow { val filter = { asset: Asset -> asset.transferableInPlanks.isPositive() } return searchAssetsByTokensInternalFlow( @@ -54,7 +54,7 @@ class ByTokensAssetSearchInteractor( queryFlow: Flow, externalBalancesFlow: Flow>, coroutineScope: CoroutineScope - ): Flow { + ): Flow { val filterFlow = assetSearchUseCase.getAvailableSwapAssets(forAsset, coroutineScope).map { availableAssetsForSwap -> val filter: AssetSearchFilter = { asset -> val chainAsset = asset.token.configuration @@ -71,14 +71,14 @@ class ByTokensAssetSearchInteractor( override fun searchReceiveAssetsFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow { + ): Flow { return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = null) } override fun searchAssetsFlow( queryFlow: Flow, externalBalancesFlow: Flow>, - ): Flow { + ): Flow { return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filter = null) } @@ -88,7 +88,7 @@ class ByTokensAssetSearchInteractor( assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), assetsComparator: Comparator = getTokenAssetBaseComparator(), filter: AssetSearchFilter?, - ): Flow { + ): Flow { val filterFlow = flowOf(filter) return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, assetGroupComparator, assetsComparator, filterFlow) @@ -100,7 +100,7 @@ class ByTokensAssetSearchInteractor( assetGroupComparator: Comparator = getTokenAssetGroupBaseComparator(), assetsComparator: Comparator = getTokenAssetBaseComparator(), filterFlow: Flow, - ): Flow { + ): Flow { val assetsFlow = assetSearchUseCase.filteredAssetFlow(filterFlow) val aggregatedExternalBalances = externalBalancesFlow.map { it.aggregatedBalanceByAsset() } @@ -111,7 +111,7 @@ class ByTokensAssetSearchInteractor( val assetGroups = groupAndSortAssetsByToken(filtered, externalBalances, chainsById, assetGroupComparator, assetsComparator) - AssetFlowSearchResult.ByTokens(assetGroups) + AssetsByViewModeResult.ByTokens(assetGroups) } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetExpandableAssetDecorationSettings.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetExpandableAssetDecorationSettings.kt new file mode 100644 index 0000000000..7c33240f8d --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetExpandableAssetDecorationSettings.kt @@ -0,0 +1,6 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common + +import android.view.animation.AccelerateDecelerateInterpolator +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAnimationSettings + +fun createAssetExpandableAnimationSettings() = ExpandableAnimationSettings(400, AccelerateDecelerateInterpolator()) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index 53a779c724..aca876dbb8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -1,40 +1,34 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common import io.novafoundation.nova.common.data.model.AssetViewMode -import io.novafoundation.nova.common.data.model.switch import io.novafoundation.nova.common.utils.shareInBackground -import io.novafoundation.nova.common.utils.toggle -import io.novafoundation.nova.common.utils.updateValue import io.novafoundation.nova.feature_assets.domain.WalletInteractor import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.list.AssetsListInteractor -import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.domain.assets.models.byNetworks +import io.novafoundation.nova.feature_assets.domain.assets.models.byTokens import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem -import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi -import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.first class AssetListMixinFactory( private val walletInteractor: WalletInteractor, private val assetsListInteractor: AssetsListInteractor, - private val currencyInteractor: CurrencyInteractor, - private val externalBalancesInteractor: ExternalBalancesInteractor + private val externalBalancesInteractor: ExternalBalancesInteractor, + private val expandableAssetsMixinFactory: ExpandableAssetsMixinFactory ) { fun create(coroutineScope: CoroutineScope): AssetListMixin = RealAssetListMixin( walletInteractor, assetsListInteractor, - currencyInteractor, externalBalancesInteractor, + expandableAssetsMixinFactory, coroutineScope ) } @@ -47,8 +41,6 @@ interface AssetListMixin { val assetsFlow: Flow> - val filteredAssetsFlow: Flow> - val assetModelsFlow: Flow> fun expandToken(tokenGroupUi: TokenGroupUi) @@ -59,69 +51,45 @@ interface AssetListMixin { class RealAssetListMixin( private val walletInteractor: WalletInteractor, private val assetsListInteractor: AssetsListInteractor, - private val currencyInteractor: CurrencyInteractor, private val externalBalancesInteractor: ExternalBalancesInteractor, + private val expandableAssetsMixinFactory: ExpandableAssetsMixinFactory, private val coroutineScope: CoroutineScope ) : AssetListMixin, CoroutineScope by coroutineScope { override val assetsFlow = walletInteractor.assetsFlow() .shareInBackground() - override val filteredAssetsFlow = walletInteractor.filterAssets(assetsFlow) - .shareInBackground() - - private val selectedCurrency = currencyInteractor.observeSelectCurrency() + private val filteredAssetsFlow = walletInteractor.filterAssets(assetsFlow) .shareInBackground() override val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() .shareInBackground() - private val expandedTokenIdsFlow = MutableStateFlow(setOf()) - override val assetsViewModeFlow = assetsListInteractor.assetsViewModeFlow() .shareInBackground() - override val assetModelsFlow = combine( + private val assetsByViewMode = combine( filteredAssetsFlow, - selectedCurrency, externalBalancesFlow, - assetsViewModeFlow, - expandedTokenIdsFlow - ) { assets, currency, externalBalances, viewMode, expandedTokens -> + assetsViewModeFlow + ) { assets, externalBalances, viewMode -> when (viewMode) { - AssetViewMode.NETWORKS -> walletInteractor.groupAssetsByNetwork(assets, externalBalances).mapGroupedAssetsToUi(currency) - AssetViewMode.TOKENS -> walletInteractor.groupAssetsByToken(assets, externalBalances) - .mapGroupedAssetsToUi( - assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } - ) + AssetViewMode.NETWORKS -> walletInteractor.groupAssetsByNetwork(assets, externalBalances).byNetworks() + AssetViewMode.TOKENS -> walletInteractor.groupAssetsByToken(assets, externalBalances).byTokens() } }.distinctUntilChanged() .shareInBackground() - override suspend fun switchViewMode() { - expandedTokenIdsFlow.value = emptySet() + private val expandableAssetsMixin = expandableAssetsMixinFactory.create(assetsByViewMode) - val assetViewMode = assetsViewModeFlow.first() - assetsListInteractor.setAssetViewMode(assetViewMode.switch()) - } + override val assetModelsFlow = expandableAssetsMixin.assetModelsFlow + .shareInBackground() override fun expandToken(tokenGroupUi: TokenGroupUi) { - expandedTokenIdsFlow.updateValue { it.toggle(tokenGroupUi.itemId) } + expandableAssetsMixin.expandToken(tokenGroupUi) } - private fun filterTokens(groupId: String, assets: List, expandedGroups: Set): List { - if (groupId in expandedGroups) { - return filterIfSingleItem(assets) - } - - return emptyList() - } - - private fun filterIfSingleItem(assets: List): List { - return if (assets.size <= 1) { - emptyList() - } else { - assets - } + override suspend fun switchViewMode() { + expandableAssetsMixin.switchViewMode() } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt new file mode 100644 index 0000000000..a59d857965 --- /dev/null +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -0,0 +1,84 @@ +package io.novafoundation.nova.feature_assets.presentation.balance.common + +import io.novafoundation.nova.common.data.model.switch +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository +import io.novafoundation.nova.common.utils.toggle +import io.novafoundation.nova.common.utils.updateValue +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult +import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi +import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi +import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine + +class ExpandableAssetsMixinFactory( + private val currencyInteractor: CurrencyInteractor, + private val assetsViewModeRepository: AssetsViewModeRepository +) { + + fun create(assetsFlow: Flow): ExpandableAssetsMixin { + return RealExpandableAssetsMixin(assetsFlow, currencyInteractor, assetsViewModeRepository) + } +} + +interface ExpandableAssetsMixin { + + val assetModelsFlow: Flow> + + fun expandToken(tokenGroupUi: TokenGroupUi) + suspend fun switchViewMode() +} + +class RealExpandableAssetsMixin( + assetsFlow: Flow, + currencyInteractor: CurrencyInteractor, + private val assetsViewModeRepository: AssetsViewModeRepository, +) : ExpandableAssetsMixin { + + private val selectedCurrency = currencyInteractor.observeSelectCurrency() + + private val expandedTokenIdsFlow = MutableStateFlow(setOf()) + + override val assetModelsFlow: Flow> = combine( + assetsFlow, + expandedTokenIdsFlow, + selectedCurrency + ) { assetesByViewMode, expandedTokens, currency -> + when (assetesByViewMode) { + is AssetsByViewModeResult.ByNetworks -> assetesByViewMode.assets.mapGroupedAssetsToUi(currency) + is AssetsByViewModeResult.ByTokens -> assetesByViewMode.tokens.mapGroupedAssetsToUi( + assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } + ) + } + } + + override fun expandToken(tokenGroupUi: TokenGroupUi) { + expandedTokenIdsFlow.updateValue { it.toggle(tokenGroupUi.itemId) } + } + + override suspend fun switchViewMode() { + expandedTokenIdsFlow.value = emptySet() + + val assetViewMode = assetsViewModeRepository.getAssetViewMode() + assetsViewModeRepository.setAssetsViewMode(assetViewMode.switch()) + } + + private fun filterTokens(groupId: String, assets: List, expandedGroups: Set): List { + if (groupId in expandedGroups) { + return filterIfSingleItem(assets) + } + + return emptyList() + } + + private fun filterIfSingleItem(assets: List): List { + return if (assets.size <= 1) { + emptyList() + } else { + assets + } + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index d85863cc68..2fdd80a129 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -4,14 +4,12 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.animation.AccelerateDecelerateInterpolator import androidx.recyclerview.widget.ConcatAdapter import coil.ImageLoader import dev.chrisbanes.insetter.applyInsetter import io.novafoundation.nova.common.base.BaseFragment import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.hideKeyboard -import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAnimationSettings import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi @@ -22,6 +20,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTo import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensItemAnimator import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.applyDefaultTo +import io.novafoundation.nova.feature_assets.presentation.balance.common.createAssetExpandableAnimationSettings import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetsHeaderAdapter import io.novafoundation.nova.feature_assets.presentation.model.AssetModel @@ -71,7 +70,7 @@ class BalanceListFragment : balanceListAssets.setHasFixedSize(true) balanceListAssets.adapter = adapter - val animationSettings = ExpandableAnimationSettings(400, AccelerateDecelerateInterpolator()) + val animationSettings = createAssetExpandableAnimationSettings() val animator = ExpandableAnimator(balanceListAssets, animationSettings, assetsAdapter) balanceListAssets.addItemDecoration(AssetTokensDecoration(requireContext(), assetsAdapter, animator)) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt index 99c9f35b5c..cbdc7f0cc5 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt @@ -20,7 +20,6 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAcco import io.novafoundation.nova.feature_account_api.domain.model.MetaAccount import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.WalletInteractor -import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.list.AssetsListInteractor import io.novafoundation.nova.feature_assets.domain.breakdown.BalanceBreakdown import io.novafoundation.nova.feature_assets.domain.breakdown.BalanceBreakdownInteractor @@ -70,7 +69,6 @@ class BalanceListViewModel( private val router: AssetsRouter, private val currencyInteractor: CurrencyInteractor, private val balanceBreakdownInteractor: BalanceBreakdownInteractor, - private val externalBalancesInteractor: ExternalBalancesInteractor, private val resourceManager: ResourceManager, private val walletConnectSessionsUseCase: WalletConnectSessionsUseCase, private val swapAvailabilityInteractor: SwapAvailabilityInteractor, @@ -139,7 +137,7 @@ class BalanceListViewModel( .inBackground() .share() - val shouldShowPlaceholderFlow = assetListMixin.filteredAssetsFlow.map { it.isEmpty() } + val shouldShowPlaceholderFlow = assetListMixin.assetModelsFlow.map { it.isEmpty() } val balanceBreakdownFlow = balanceBreakdown.map { val currency = selectedCurrency.first() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt index dfdcbc7bc4..297571824a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt @@ -20,6 +20,7 @@ import io.novafoundation.nova.feature_assets.domain.assets.list.AssetsListIntera import io.novafoundation.nova.feature_assets.domain.breakdown.BalanceBreakdownInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetListMixinFactory +import io.novafoundation.nova.feature_assets.presentation.balance.common.ExpandableAssetsMixinFactory import io.novafoundation.nova.feature_assets.presentation.balance.list.BalanceListViewModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_nft_api.data.repository.NftRepository @@ -59,14 +60,14 @@ class BalanceListModule { fun provideAssetListMixinFactory( walletInteractor: WalletInteractor, assetsListInteractor: AssetsListInteractor, - currencyInteractor: CurrencyInteractor, - externalBalancesInteractor: ExternalBalancesInteractor + externalBalancesInteractor: ExternalBalancesInteractor, + expandableAssetsMixinFactory: ExpandableAssetsMixinFactory ): AssetListMixinFactory { return AssetListMixinFactory( walletInteractor, assetsListInteractor, - currencyInteractor, - externalBalancesInteractor + externalBalancesInteractor, + expandableAssetsMixinFactory ) } @@ -80,7 +81,6 @@ class BalanceListModule { router: AssetsRouter, currencyInteractor: CurrencyInteractor, balanceBreakdownInteractor: BalanceBreakdownInteractor, - externalBalancesInteractor: ExternalBalancesInteractor, resourceManager: ResourceManager, walletConnectSessionsUseCase: WalletConnectSessionsUseCase, swapAvailabilityInteractor: SwapAvailabilityInteractor, @@ -93,7 +93,6 @@ class BalanceListModule { router = router, currencyInteractor = currencyInteractor, balanceBreakdownInteractor = balanceBreakdownInteractor, - externalBalancesInteractor = externalBalancesInteractor, resourceManager = resourceManager, walletConnectSessionsUseCase = walletConnectSessionsUseCase, swapAvailabilityInteractor = swapAvailabilityInteractor, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt index b85657e37a..2dd034331a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt @@ -13,14 +13,17 @@ import io.novafoundation.nova.common.utils.applyStatusBarInsets import io.novafoundation.nova.common.utils.bindTo import io.novafoundation.nova.common.utils.keyboard.hideSoftKeyboard import io.novafoundation.nova.common.utils.keyboard.showSoftKeyboard +import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator import io.novafoundation.nova.common.utils.setVisible -import io.novafoundation.nova.common.utils.submitListPreservingViewPoint import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent +import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensDecoration +import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensItemAnimator import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.AssetBaseDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.applyDefaultTo +import io.novafoundation.nova.feature_assets.presentation.balance.common.createAssetExpandableAnimationSettings import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import kotlinx.android.synthetic.main.fragment_asset_search.searchAssetContainer @@ -59,8 +62,13 @@ class AssetSearchFragment : searchAssetList.setHasFixedSize(true) searchAssetList.adapter = assetsAdapter + val animationSettings = createAssetExpandableAnimationSettings() + val animator = ExpandableAnimator(searchAssetList, animationSettings, assetsAdapter) + + searchAssetList.addItemDecoration(AssetTokensDecoration(requireContext(), assetsAdapter, animator)) + searchAssetList.itemAnimator = AssetTokensItemAnimator(animationSettings, animator) + AssetBaseDecoration.applyDefaultTo(searchAssetList, assetsAdapter) - searchAssetList.itemAnimator = null searchAssetSearch.cancel.setOnClickListener { viewModel.cancelClicked() @@ -85,11 +93,7 @@ class AssetSearchFragment : searchAssetsPlaceholder.setVisible(data.isEmpty()) searchAssetList.setVisible(data.isNotEmpty()) - assetsAdapter.submitListPreservingViewPoint( - data = data, - into = searchAssetList, - extraDiffCompletedCallback = { searchAssetList.invalidateItemDecorations() } - ) + assetsAdapter.submitList(data) { searchAssetList.invalidateItemDecorations() } } } @@ -104,6 +108,13 @@ class AssetSearchFragment : } override fun tokenGroupClicked(tokenGroup: TokenGroupUi) { - showMessage("Not implemented yet") + if (tokenGroup.groupType is TokenGroupUi.GroupType.SingleItem) { + viewModel.assetClicked(tokenGroup.groupType.asset) + } else { + val itemAnimator = searchAssetList.itemAnimator as AssetTokensItemAnimator + itemAnimator.prepareForAnimation() + + viewModel.assetListMixin.expandToken(tokenGroup) + } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt index 6642190511..1ceb18ebe1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt @@ -1,47 +1,32 @@ package io.novafoundation.nova.feature_assets.presentation.balance.search import io.novafoundation.nova.common.base.BaseViewModel -import io.novafoundation.nova.common.utils.inBackground import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.AssetsRouter -import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi +import io.novafoundation.nova.feature_assets.presentation.balance.common.ExpandableAssetsMixinFactory import io.novafoundation.nova.feature_assets.presentation.model.AssetModel -import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.distinctUntilChanged class AssetSearchViewModel( private val router: AssetsRouter, interactorFactory: AssetSearchInteractorFactory, - currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor, + expandableAssetsMixinFactory: ExpandableAssetsMixinFactory ) : BaseViewModel() { val interactor = interactorFactory.createByAssetViewMode() val query = MutableStateFlow("") - private val selectedCurrency = currencyInteractor.observeSelectCurrency() - .inBackground() - .share() - private val externalBalances = externalBalancesInteractor.observeExternalBalances() - val searchResults = combine( - interactor.searchAssetsFlow(query, externalBalances), - selectedCurrency, - ) { assets, currency -> - when (assets) { - is AssetFlowSearchResult.ByNetworks -> assets.assets.mapGroupedAssetsToUi(currency) - is AssetFlowSearchResult.ByTokens -> assets.tokens.mapGroupedAssetsToUi() - } - } - .distinctUntilChanged() - .shareInBackground() + private val assetsFlow = interactor.searchAssetsFlow(query, externalBalances) + + val assetListMixin = expandableAssetsMixinFactory.create(assetsFlow) + + val searchResults = assetListMixin.assetModelsFlow fun cancelClicked() { router.back() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt index 29a57940bd..ef96d43cd7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt @@ -11,8 +11,8 @@ import io.novafoundation.nova.common.di.viewmodel.ViewModelModule import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.balance.common.ExpandableAssetsMixinFactory import io.novafoundation.nova.feature_assets.presentation.balance.search.AssetSearchViewModel -import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor @Module(includes = [ViewModelModule::class]) class AssetSearchModule { @@ -28,14 +28,14 @@ class AssetSearchModule { fun provideViewModel( router: AssetsRouter, interactorFactory: AssetSearchInteractorFactory, - currencyInteractor: CurrencyInteractor, - externalBalancesInteractor: ExternalBalancesInteractor + externalBalancesInteractor: ExternalBalancesInteractor, + expandableAssetsMixinFactory: ExpandableAssetsMixinFactory ): ViewModel { return AssetSearchViewModel( router = router, interactorFactory = interactorFactory, - currencyInteractor = currencyInteractor, - externalBalancesInteractor = externalBalancesInteractor + externalBalancesInteractor = externalBalancesInteractor, + expandableAssetsMixinFactory = expandableAssetsMixinFactory ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt index 14569eee7c..42cfa860d5 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt @@ -3,7 +3,7 @@ package io.novafoundation.nova.feature_assets.presentation.buy.flow.asset import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin @@ -36,7 +36,7 @@ class AssetBuyFlowViewModel( val buyMixin = buyMixinFactory.create(scope = this) - override fun searchAssetsFlow(): Flow { + override fun searchAssetsFlow(): Flow { return interactor.buyAssetSearch(query, externalBalancesFlow) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index 364d2d9a2a..a703a589e8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -8,7 +8,7 @@ import io.novafoundation.nova.common.view.PlaceholderModel import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult import io.novafoundation.nova.feature_assets.domain.assets.models.groupList import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork @@ -71,16 +71,16 @@ abstract class AssetFlowViewModel( router.back() } - abstract fun searchAssetsFlow(): Flow + abstract fun searchAssetsFlow(): Flow abstract fun assetClicked(assetModel: AssetModel) abstract fun tokenClicked(tokenGroup: TokenGroupUi) - private fun mapAssets(searchResult: AssetFlowSearchResult, currency: Currency): List { + private fun mapAssets(searchResult: AssetsByViewModeResult, currency: Currency): List { return when (searchResult) { - is AssetFlowSearchResult.ByNetworks -> mapNetworkAssets(searchResult.assets, currency) - is AssetFlowSearchResult.ByTokens -> mapTokensAssets(searchResult.tokens) + is AssetsByViewModeResult.ByNetworks -> mapNetworkAssets(searchResult.assets, currency) + is AssetsByViewModeResult.ByTokens -> mapTokensAssets(searchResult.tokens) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt index 2678ba2a6c..225c41442f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt @@ -3,7 +3,7 @@ package io.novafoundation.nova.feature_assets.presentation.receive.flow.asset import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.AssetsRouter @@ -32,7 +32,7 @@ class AssetReceiveFlowViewModel( externalBalancesInteractor, resourceManager, ) { - override fun searchAssetsFlow(): Flow { + override fun searchAssetsFlow(): Flow { return interactor.searchReceiveAssetsFlow(query, externalBalancesFlow) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt index 935d9f6179..da7b1aa180 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt @@ -5,7 +5,7 @@ import io.novafoundation.nova.common.view.PlaceholderModel import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup @@ -45,7 +45,7 @@ class AssetSendFlowViewModel( resourceManager, ) { - override fun searchAssetsFlow(): Flow { + override fun searchAssetsFlow(): Flow { return interactor.sendAssetSearch(query, externalBalancesFlow) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index 0197394adb..3adaa7e0e2 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -1,6 +1,5 @@ package io.novafoundation.nova.feature_assets.presentation.swap.asset -import android.util.Log import androidx.annotation.StringRes import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.resources.ResourceManager @@ -8,7 +7,7 @@ import io.novafoundation.nova.common.utils.launchUnit import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor -import io.novafoundation.nova.feature_assets.domain.assets.models.AssetFlowSearchResult +import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup @@ -68,7 +67,7 @@ class AssetSwapFlowViewModel( } } - override fun searchAssetsFlow(): Flow { + override fun searchAssetsFlow(): Flow { return interactor.searchSwapAssetsFlow( forAsset = swapPayload.constraintDirectionsAsset?.fullChainAssetId, queryFlow = query, From d605612c8f83accf62c1fe0e65b3db1b76cfc773 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 11:30:22 +0100 Subject: [PATCH 32/78] Update AssetNetworksInteractor.kt --- .../feature_assets/domain/networks/AssetNetworksInteractor.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt index 688385d856..db36fa1921 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt @@ -4,7 +4,6 @@ import io.novafoundation.nova.common.utils.TokenSymbol import io.novafoundation.nova.common.utils.filterList import io.novafoundation.nova.common.utils.filterSet import io.novafoundation.nova.common.utils.flowOfAll -import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchFilter import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchUseCase import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork @@ -13,7 +12,6 @@ import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetBaseComp import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetGroupBaseComparator import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByToken import io.novafoundation.nova.feature_swap_api.domain.swap.SwapService -import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletRepository import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance import io.novafoundation.nova.feature_wallet_api.domain.model.aggregatedBalanceByAsset @@ -27,7 +25,6 @@ import io.novasama.substrate_sdk_android.hash.isPositive import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map From 45ab24994b8a8bfb6045141f1c76f05d32ff36db Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 12:10:24 +0100 Subject: [PATCH 33/78] Reset scroll position when search --- .../presentation/balance/search/AssetSearchFragment.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt index 2dd034331a..fa310f6b53 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt @@ -89,6 +89,12 @@ class AssetSearchFragment : override fun subscribe(viewModel: AssetSearchViewModel) { searchAssetSearch.searchInput.content.bindTo(viewModel.query, lifecycleScope) + viewModel.query.observe { + searchAssetList.post { + searchAssetList.layoutManager!!.scrollToPosition(0) + } + } + viewModel.searchResults.observe { data -> searchAssetsPlaceholder.setVisible(data.isEmpty()) searchAssetList.setVisible(data.isNotEmpty()) From 068be0641f0ed7ecc7964f9a94b17d3b45feb2a5 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 13:37:14 +0100 Subject: [PATCH 34/78] Change providing colored icons --- common/build.gradle | 3 + ...Service.kt => AssetsIconModeRepository.kt} | 10 +- .../nova/common/di/CommonApi.kt | 65 +++---- .../nova/common/di/modules/CommonModule.kt | 21 ++- .../common/presentation/AssetIconProvider.kt | 34 ++++ .../nova/common/view/AmountView.kt | 7 +- .../presenatation/chain/ChainUi.kt | 9 +- .../di/AssetsFeatureDependencies.kt | 160 +++++++++--------- .../di/modules/ManageTokensCommonModule.kt | 4 +- .../domain/common/TokenAssetSorting.kt | 2 +- .../tokens/manage/ManageTokenInteractor.kt | 2 +- .../balance/common/AssetListMixin.kt | 7 +- .../common/holders/NetworkAssetViewHolder.kt | 3 +- .../holders/TokenAssetGroupViewHolder.kt | 3 +- .../common/holders/TokenAssetViewHolder.kt | 3 +- .../common/mappers/NetworkAssetMappers.kt | 13 +- .../common/mappers/TokenAssetMappers.kt | 20 ++- .../balance/detail/AssetDetailsModel.kt | 2 + .../balance/detail/BalanceDetailFragment.kt | 3 +- .../balance/detail/BalanceDetailViewModel.kt | 8 +- .../balance/detail/di/BalanceDetailModule.kt | 13 +- .../balance/list/di/BalanceListModule.kt | 3 + .../list/model/items/NetworkAssetUi.kt | 3 +- .../balance/list/model/items/TokenAssetUi.kt | 8 +- .../balance/list/model/items/TokenGroupUi.kt | 3 +- .../balance/search/AssetSearchViewModel.kt | 4 +- .../balance/search/di/AssetSearchModule.kt | 7 +- .../buy/flow/asset/AssetBuyFlowViewModel.kt | 3 + .../buy/flow/asset/di/AssetBuyFlowModule.kt | 7 +- .../flow/asset/AssetFlowViewModel.kt | 6 +- .../presentation/receive/ReceiveFragment.kt | 3 +- .../presentation/receive/ReceiveViewModel.kt | 5 +- .../presentation/receive/di/ReceiveModule.kt | 3 + .../flow/asset/AssetReceiveFlowViewModel.kt | 3 + .../flow/asset/di/AssetReceiveFlowModule.kt | 7 +- .../receive/model/TokenReceiver.kt | 3 +- .../send/flow/asset/AssetSendFlowViewModel.kt | 7 +- .../send/flow/asset/di/AssetSendFlowModule.kt | 7 +- .../swap/asset/AssetSwapFlowViewModel.kt | 9 +- .../swap/asset/di/AssetSwapFlowModule.kt | 7 +- .../tokens/manage/ManageTokensAdapter.kt | 3 +- .../manage/chain/ManageChainTokensFragment.kt | 3 +- .../manage/model/MultiChainTokenModel.kt | 7 +- .../detail/di/ExtrinsicDetailModule.kt | 5 +- .../extrinsic/ExtrinsicDetailFragment.kt | 3 +- .../extrinsic/ExtrinsicDetailViewModel.kt | 6 +- .../detail/swap/SwapDetailViewModel.kt | 6 +- .../detail/swap/di/SwapDetailModule.kt | 5 +- .../history/mixin/OperationMappers.kt | 5 +- .../mixin/TransactionHistoryProvider.kt | 6 +- .../di/CrowdloanFeatureDependencies.kt | 19 ++- .../confirm/ConfirmContributeFragment.kt | 2 +- .../confirm/ConfirmContributeViewModel.kt | 4 +- .../confirm/di/ConfirmContributeModule.kt | 3 + .../select/CrowdloanContributeFragment.kt | 2 +- .../select/CrowdloanContributeViewModel.kt | 4 +- .../select/di/CrowdloanContributeModule.kt | 3 + .../domain/sign/evm/EvmSignInteractor.kt | 2 +- .../di/GovernanceFeatureDependencies.kt | 35 ++-- .../di/GovernanceFeatureModule.kt | 6 +- .../presentation/track/TrackFormatter.kt | 21 ++- .../di/SwapFeatureDependencies.kt | 3 + .../confirmation/SwapConfirmationViewModel.kt | 6 +- .../confirmation/di/SwapConfirmationModule.kt | 7 +- .../main/di/SwapMainSettingsModule.kt | 6 +- .../main/input/SwapAmountInputMixin.kt | 2 +- .../main/input/SwapAmountInputMixinFactory.kt | 13 +- .../presentation/views/SwapAmountInputView.kt | 3 +- .../feature_wallet_api/data/mappers/Asset.kt | 5 +- .../di/common/SelectableAssetUseCaseModule.kt | 3 + .../amountChooser/AmountChooserProvider.kt | 8 +- .../assetSelector/AssetSelectorProvider.kt | 7 +- .../presentation/model/AssetModel.kt | 4 +- .../presentation/model/ChooseAmountModel.kt | 12 +- .../view/AssetSelectorBottomSheet.kt | 3 +- .../presentation/view/AssetSelectorView.kt | 3 +- .../view/amount/ChooseAmountInputView.kt | 7 +- .../view/amount/ChooseAmountView.kt | 5 +- .../repository/RealChainAssetRepository.kt | 8 +- .../di/WalletFeatureDependencies.kt | 62 +++---- .../di/WalletFeatureModule.kt | 13 +- runtime/build.gradle | 3 - .../nova/runtime/di/ChainRegistryModule.kt | 9 +- .../nova/runtime/di/RuntimeDependencies.kt | 4 +- .../nova/runtime/di/RuntimeModule.kt | 8 +- .../runtime/multiNetwork/ChainRegistry.kt | 9 +- .../chain/mappers/DomainToLocalChainMapper.kt | 2 +- .../chain/mappers/LocalToDomainChainMapper.kt | 25 +-- .../RemoteToDomainChainMapperFacade.kt | 8 +- .../runtime/multiNetwork/chain/model/Chain.kt | 16 +- 90 files changed, 561 insertions(+), 343 deletions(-) rename common/src/main/java/io/novafoundation/nova/common/data/repository/{AssetsIconModeService.kt => AssetsIconModeRepository.kt} (89%) create mode 100644 common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt diff --git a/common/build.gradle b/common/build.gradle index 0a119a8950..7b2dfa6b78 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -42,6 +42,9 @@ android { buildConfigField "String", "LEDGER_BLEUTOOTH_GUIDE", "\"https://support.ledger.com/hc/en-us/articles/360019138694-Set-up-Bluetooth-connection\"" buildConfigField "String", "APP_UPDATE_SOURCE_LINK", "\"https://play.google.com/store/apps/details?id=io.novafoundation.nova.market\"" + + buildConfigField "String", "ASSET_COLORED_ICON_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/icons/tokens/colored\"" + buildConfigField "String", "ASSET_WHITE_ICON_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/icons/tokens/white\"" } buildTypes { diff --git a/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsIconModeService.kt b/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsIconModeRepository.kt similarity index 89% rename from common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsIconModeService.kt rename to common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsIconModeRepository.kt index 7d75ee2560..0a2455e699 100644 --- a/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsIconModeService.kt +++ b/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsIconModeRepository.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext -interface AssetsIconModeService { +interface AssetsIconModeRepository { fun assetsIconModeFlow(): Flow suspend fun setAssetsIconMode(assetsViewMode: AssetIconMode) @@ -18,9 +18,9 @@ interface AssetsIconModeService { private const val PREFS_ASSETS_ICON_MODE = "PREFS_ASSETS_ICON_MODE" private val ASSET_ICON_MODE_DEFAULT = AssetIconMode.COLORED -class RealAssetsIconModeService( +class RealAssetsIconModeRepository( private val preferences: Preferences -) : AssetsIconModeService { +) : AssetsIconModeRepository { override fun assetsIconModeFlow(): Flow { return preferences.stringFlow(PREFS_ASSETS_ICON_MODE) @@ -40,14 +40,14 @@ class RealAssetsIconModeService( private fun AssetIconMode.toPrefsValue(): String { return when (this) { AssetIconMode.COLORED -> "colored" - AssetIconMode.WHITE -> "solid" + AssetIconMode.WHITE -> "white" } } private fun String.fromPrefsValue(): AssetIconMode? { return when (this) { "colored" -> AssetIconMode.COLORED - "solid" -> AssetIconMode.WHITE + "white" -> AssetIconMode.WHITE else -> null } } diff --git a/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt b/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt index 02bafdac71..359cb144d8 100644 --- a/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt +++ b/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt @@ -14,7 +14,7 @@ import io.novafoundation.nova.common.data.network.HttpExceptionHandler import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser import io.novafoundation.nova.common.data.network.rpc.SocketSingleRequestExecutor -import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.repository.AssetsViewModeService import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1 @@ -31,6 +31,7 @@ import io.novafoundation.nova.common.mixin.api.CustomDialogDisplayer import io.novafoundation.nova.common.mixin.api.NetworkStateMixin import io.novafoundation.nova.common.mixin.condition.ConditionMixinFactory import io.novafoundation.nova.common.mixin.hints.ResourcesHintsMixinFactory +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.AppVersionProvider import io.novafoundation.nova.common.resources.ClipboardManager import io.novafoundation.nova.common.resources.ContextManager @@ -65,6 +66,36 @@ import java.util.Random interface CommonApi { + val systemCallExecutor: SystemCallExecutor + + val actionAwaitableMixinFactory: ActionAwaitableMixin.Factory + + val resourcesHintsMixinFactory: ResourcesHintsMixinFactory + + val okHttpClient: OkHttpClient + + val fileCache: FileCache + + val permissionsAskerFactory: PermissionsAskerFactory + + val bluetoothManager: BluetoothManager + + val locationManager: LocationManager + + val listChooserMixinFactory: ListChooserMixin.Factory + + val partialRetriableMixinFactory: PartialRetriableMixin.Factory + + val automaticInteractionGate: AutomaticInteractionGate + + val bannerVisibilityRepository: BannerVisibilityRepository + + val provideActivityIntentProvider: ActivityIntentProvider + + val googleApiAvailabilityProvider: GoogleApiAvailabilityProvider + + val coinGeckoLinkParser: CoinGeckoLinkParser + fun computationalCache(): ComputationalCache fun imageLoader(): ImageLoader @@ -158,35 +189,7 @@ interface CommonApi { fun assetsViewModeRepository(): AssetsViewModeService - fun assetsIconModeService(): AssetsIconModeService + fun assetsIconModeService(): AssetsIconModeRepository - val systemCallExecutor: SystemCallExecutor - - val actionAwaitableMixinFactory: ActionAwaitableMixin.Factory - - val resourcesHintsMixinFactory: ResourcesHintsMixinFactory - - val okHttpClient: OkHttpClient - - val fileCache: FileCache - - val permissionsAskerFactory: PermissionsAskerFactory - - val bluetoothManager: BluetoothManager - - val locationManager: LocationManager - - val listChooserMixinFactory: ListChooserMixin.Factory - - val partialRetriableMixinFactory: PartialRetriableMixin.Factory - - val automaticInteractionGate: AutomaticInteractionGate - - val bannerVisibilityRepository: BannerVisibilityRepository - - val provideActivityIntentProvider: ActivityIntentProvider - - val googleApiAvailabilityProvider: GoogleApiAvailabilityProvider - - val coinGeckoLinkParser: CoinGeckoLinkParser + fun assetIconProvider(): AssetIconProvider } diff --git a/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt b/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt index c74a772484..bd8bb0367e 100644 --- a/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt +++ b/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt @@ -9,6 +9,7 @@ import coil.ImageLoader import coil.decode.SvgDecoder import dagger.Module import dagger.Provides +import io.novafoundation.nova.common.BuildConfig import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.address.CachingAddressIconGenerator import io.novafoundation.nova.common.address.StatelessAddressIconGenerator @@ -19,10 +20,10 @@ import io.novafoundation.nova.common.data.RealGoogleApiAvailabilityProvider import io.novafoundation.nova.common.data.memory.ComputationalCache import io.novafoundation.nova.common.data.memory.RealComputationalCache import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser -import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.repository.AssetsViewModeService import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository -import io.novafoundation.nova.common.data.repository.RealAssetsIconModeService +import io.novafoundation.nova.common.data.repository.RealAssetsIconModeRepository import io.novafoundation.nova.common.data.repository.RealAssetsViewModeService import io.novafoundation.nova.common.data.repository.RealBannerVisibilityRepository import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1 @@ -44,6 +45,8 @@ import io.novafoundation.nova.common.mixin.condition.ConditionMixinFactory import io.novafoundation.nova.common.mixin.condition.RealConditionMixinFactory import io.novafoundation.nova.common.mixin.hints.ResourcesHintsMixinFactory import io.novafoundation.nova.common.mixin.impl.CustomDialogProvider +import io.novafoundation.nova.common.presentation.AssetIconProvider +import io.novafoundation.nova.common.presentation.RealAssetIconProvider import io.novafoundation.nova.common.resources.AppVersionProvider import io.novafoundation.nova.common.resources.ClipboardManager import io.novafoundation.nova.common.resources.ContextManager @@ -354,9 +357,19 @@ class CommonModule { @Provides @ApplicationScope - fun assetsViewModeService(preferences: Preferences): AssetsViewModeService = RealAssetsViewModeService(preferences) + fun provideAssetsViewModeService(preferences: Preferences): AssetsViewModeService = RealAssetsViewModeService(preferences) @Provides @ApplicationScope - fun assetsIconModeService(preferences: Preferences): AssetsIconModeService = RealAssetsIconModeService(preferences) + fun provideAssetsIconModeRepository(preferences: Preferences): AssetsIconModeRepository = RealAssetsIconModeRepository(preferences) + + @Provides + @ApplicationScope + fun provideAssetIconProvider(repository: AssetsIconModeRepository): AssetIconProvider { + return RealAssetIconProvider( + repository, + BuildConfig.ASSET_COLORED_ICON_URL, + BuildConfig.ASSET_WHITE_ICON_URL, + ) + } } diff --git a/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt b/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt new file mode 100644 index 0000000000..6d262086f7 --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt @@ -0,0 +1,34 @@ +package io.novafoundation.nova.common.presentation + +import io.novafoundation.nova.common.R +import io.novafoundation.nova.common.data.model.AssetIconMode +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository +import io.novafoundation.nova.common.utils.images.Icon +import io.novafoundation.nova.common.utils.images.asIcon + +interface AssetIconProvider { + + val fallbackIcon: Icon + + fun getAssetIcon(iconName: String?, fallback: Icon = fallbackIcon): Icon +} + +class RealAssetIconProvider( + private val assetsIconModeRepository: AssetsIconModeRepository, + private val coloredBaseUrl: String, + private val whiteBaseUrl: String +) : AssetIconProvider { + + override val fallbackIcon: Icon = R.drawable.ic_nova.asIcon() + + override fun getAssetIcon(iconName: String?, fallback: Icon): Icon { + if (iconName == null) return fallback + + val iconUrl = when (assetsIconModeRepository.getIconMode()) { + AssetIconMode.COLORED -> "$coloredBaseUrl/$iconName" + AssetIconMode.WHITE -> "$coloredBaseUrl/$whiteBaseUrl" + } + + return iconUrl.asIcon() + } +} diff --git a/common/src/main/java/io/novafoundation/nova/common/view/AmountView.kt b/common/src/main/java/io/novafoundation/nova/common/view/AmountView.kt index 1f06343917..2cb0e6491a 100644 --- a/common/src/main/java/io/novafoundation/nova/common/view/AmountView.kt +++ b/common/src/main/java/io/novafoundation/nova/common/view/AmountView.kt @@ -8,9 +8,10 @@ import android.view.View import android.widget.EditText import androidx.constraintlayout.widget.ConstraintLayout import coil.ImageLoader -import coil.load import io.novafoundation.nova.common.R import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.common.utils.images.Icon +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextOrHide import io.novafoundation.nova.common.view.shape.getBlockDrawable import io.novafoundation.nova.common.view.shape.getCornersStateDrawable @@ -87,8 +88,8 @@ class AmountView @JvmOverloads constructor( stakingAssetImage.setImageDrawable(image) } - fun loadAssetImage(imageUrl: String?) { - stakingAssetImage.load(imageUrl, imageLoader) + fun loadAssetImage(icon: Icon) { + stakingAssetImage.setIcon(icon, imageLoader) } fun setAssetName(name: String) { diff --git a/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt b/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt index a5f61e4aa0..715f73de83 100644 --- a/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt +++ b/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt @@ -6,6 +6,7 @@ import android.widget.ImageView import coil.ImageLoader import coil.load import coil.request.ImageRequest +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.common.utils.images.asIcon import io.novafoundation.nova.feature_account_api.R @@ -45,10 +46,6 @@ fun ImageView.loadTokenIcon(icon: String?, imageLoader: ImageLoader) { } } -fun Chain.Asset.icon(): Icon { - return iconUrl?.asIcon() ?: ASSET_ICON_PLACEHOLDER.asIcon() -} - fun Chain.iconOrFallback(): Icon { return icon?.asIcon() ?: chainIconFallback() } @@ -60,3 +57,7 @@ fun String?.asIconOrFallback(): Icon { fun chainIconFallback(): Icon { return R.drawable.ic_fallback_network_icon.asIcon() } + +fun AssetIconProvider.getAssetIcon(asset: Chain.Asset, fallbackIcon: Icon = this.fallbackIcon): Icon { + return this.getAssetIcon(asset.icon, fallbackIcon) +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt index ee8bc8885c..a1afb2e043 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt @@ -17,6 +17,7 @@ import io.novafoundation.nova.common.data.storage.encrypt.EncryptedPreferences import io.novafoundation.nova.common.interfaces.FileProvider import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin import io.novafoundation.nova.common.mixin.hints.ResourcesHintsMixinFactory +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ClipboardManager import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.QrCodeGenerator @@ -88,6 +89,88 @@ import javax.inject.Named interface AssetsFeatureDependencies { + val assetsSourceRegistry: AssetSourceRegistry + + val addressInputMixinFactory: AddressInputMixinFactory + + val multiChainQrSharingFactory: MultiChainQrSharingFactory + + val walletUiUseCase: WalletUiUseCase + + val computationalCache: ComputationalCache + + val actionAwaitableMixinFactory: ActionAwaitableMixin.Factory + + val crossChainTraRepository: CrossChainTransfersRepository + + val crossChainWeigher: CrossChainWeigher + + val crossChainTransactor: CrossChainTransactor + + val resourcesHintsMixinFactory: ResourcesHintsMixinFactory + + val parachainInfoRepository: ParachainInfoRepository + + val watchOnlyMissingKeysPresenter: WatchOnlyMissingKeysPresenter + + val balanceLocksRepository: BalanceLocksRepository + + val chainAssetRepository: ChainAssetRepository + + val erc20Standard: Erc20Standard + + val externalBalanceRepository: ExternalBalanceRepository + + val pooledBalanceUpdaterFactory: PooledBalanceUpdaterFactory + + val paymentUpdaterFactory: PaymentUpdaterFactory + + val locksUpdaterFactory: BalanceLocksUpdaterFactory + + val accountUpdateScope: AccountUpdateScope + + val storageSharedRequestBuilderFactory: StorageSharedRequestsBuilderFactory + + val poolDisplayUseCase: PoolDisplayUseCase + + val poolAccountDerivation: PoolAccountDerivation + + val operationDao: OperationDao + + val coinPriceRepository: CoinPriceRepository + + val swapSettingsStateProvider: SwapSettingsStateProvider + + val swapService: SwapService + + val swapAvailabilityInteractor: SwapAvailabilityInteractor + + val bannerVisibilityRepository: BannerVisibilityRepository + + val buyMixinFactory: BuyMixin.Factory + + val buyMixinUi: BuyMixinUi + + val crossChainTransfersUseCase: CrossChainTransfersUseCase + + val arbitraryTokenUseCase: ArbitraryTokenUseCase + + val swapRateFormatter: SwapRateFormatter + + val bottomSheetLauncher: DescriptionBottomSheetLauncher + + val selectAddressMixinFactory: SelectAddressMixin.Factory + + val chainStateRepository: ChainStateRepository + + val holdsRepository: BalanceHoldsRepository + + val holdsDao: HoldsDao + + val coinGeckoLinkParser: CoinGeckoLinkParser + + val assetIconProvider: AssetIconProvider + fun web3NamesInteractor(): Web3NamesInteractor fun contributionsInteractor(): ContributionsInteractor @@ -174,83 +257,6 @@ interface AssetsFeatureDependencies { fun walletConnectSessionsUseCase(): WalletConnectSessionsUseCase - val assetsSourceRegistry: AssetSourceRegistry - fun nftRepository(): NftRepository - val addressInputMixinFactory: AddressInputMixinFactory - - val multiChainQrSharingFactory: MultiChainQrSharingFactory - - val walletUiUseCase: WalletUiUseCase - - val computationalCache: ComputationalCache - - val actionAwaitableMixinFactory: ActionAwaitableMixin.Factory - - val crossChainTraRepository: CrossChainTransfersRepository - val crossChainWeigher: CrossChainWeigher - val crossChainTransactor: CrossChainTransactor - - val resourcesHintsMixinFactory: ResourcesHintsMixinFactory - - val parachainInfoRepository: ParachainInfoRepository - - val watchOnlyMissingKeysPresenter: WatchOnlyMissingKeysPresenter - - val balanceLocksRepository: BalanceLocksRepository - - val chainAssetRepository: ChainAssetRepository - - val erc20Standard: Erc20Standard - - val externalBalanceRepository: ExternalBalanceRepository - - val pooledBalanceUpdaterFactory: PooledBalanceUpdaterFactory - - val paymentUpdaterFactory: PaymentUpdaterFactory - - val locksUpdaterFactory: BalanceLocksUpdaterFactory - - val accountUpdateScope: AccountUpdateScope - - val storageSharedRequestBuilderFactory: StorageSharedRequestsBuilderFactory - - val poolDisplayUseCase: PoolDisplayUseCase - - val poolAccountDerivation: PoolAccountDerivation - - val operationDao: OperationDao - - val coinPriceRepository: CoinPriceRepository - - val swapSettingsStateProvider: SwapSettingsStateProvider - - val swapService: SwapService - - val swapAvailabilityInteractor: SwapAvailabilityInteractor - - val bannerVisibilityRepository: BannerVisibilityRepository - - val buyMixinFactory: BuyMixin.Factory - - val buyMixinUi: BuyMixinUi - - val crossChainTransfersUseCase: CrossChainTransfersUseCase - - val arbitraryTokenUseCase: ArbitraryTokenUseCase - - val swapRateFormatter: SwapRateFormatter - - val bottomSheetLauncher: DescriptionBottomSheetLauncher - - val selectAddressMixinFactory: SelectAddressMixin.Factory - - val chainStateRepository: ChainStateRepository - - val holdsRepository: BalanceHoldsRepository - - val holdsDao: HoldsDao - - val coinGeckoLinkParser: CoinGeckoLinkParser } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/modules/ManageTokensCommonModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/modules/ManageTokensCommonModule.kt index 00bfa90407..d4244715e4 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/modules/ManageTokensCommonModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/modules/ManageTokensCommonModule.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_assets.di.modules import dagger.Module import dagger.Provides import io.novafoundation.nova.common.di.scope.FeatureScope +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_assets.domain.tokens.AssetsDataCleaner import io.novafoundation.nova.feature_assets.domain.tokens.RealAssetsDataCleaner @@ -21,8 +22,9 @@ class ManageTokensCommonModule { @Provides @FeatureScope fun provideMultiChainTokenUiMapper( + assetIconProvider: AssetIconProvider, resourceManager: ResourceManager - ) = MultiChainTokenMapper(resourceManager) + ) = MultiChainTokenMapper(assetIconProvider, resourceManager) @Provides @FeatureScope diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt index dcf6da759a..53e97054f8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt @@ -72,7 +72,7 @@ fun getTokenAssetGroupBaseComparator( } private fun mapToTokenGroup(it: AssetWithNetwork) = TokenAssetGroup.Token( - it.asset.token.configuration.iconUrl, + it.asset.token.configuration.icon, it.asset.token.configuration.symbol.normalize(), it.asset.token.currency, it.asset.token.coinRate diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/manage/ManageTokenInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/manage/ManageTokenInteractor.kt index ebd60d114b..93f79b809a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/manage/ManageTokenInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/tokens/manage/ManageTokenInteractor.kt @@ -103,7 +103,7 @@ class RealManageTokenInteractor( MultiChainToken( id = symbol, symbol = symbol, - icon = firstAsset.iconUrl, + icon = firstAsset.icon, isSwitchable = !isLastTokenEnabled, instances = chainsWithAssets.map { (chain, asset) -> MultiChainToken.ChainTokenInstance( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index 53a779c724..a26ca88f23 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common import io.novafoundation.nova.common.data.model.AssetViewMode import io.novafoundation.nova.common.data.model.switch +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.utils.shareInBackground import io.novafoundation.nova.common.utils.toggle import io.novafoundation.nova.common.utils.updateValue @@ -24,6 +25,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first class AssetListMixinFactory( + private val assetIconProvider: AssetIconProvider, private val walletInteractor: WalletInteractor, private val assetsListInteractor: AssetsListInteractor, private val currencyInteractor: CurrencyInteractor, @@ -31,6 +33,7 @@ class AssetListMixinFactory( ) { fun create(coroutineScope: CoroutineScope): AssetListMixin = RealAssetListMixin( + assetIconProvider, walletInteractor, assetsListInteractor, currencyInteractor, @@ -57,6 +60,7 @@ interface AssetListMixin { } class RealAssetListMixin( + assetIconProvider: AssetIconProvider, private val walletInteractor: WalletInteractor, private val assetsListInteractor: AssetsListInteractor, private val currencyInteractor: CurrencyInteractor, @@ -89,9 +93,10 @@ class RealAssetListMixin( expandedTokenIdsFlow ) { assets, currency, externalBalances, viewMode, expandedTokens -> when (viewMode) { - AssetViewMode.NETWORKS -> walletInteractor.groupAssetsByNetwork(assets, externalBalances).mapGroupedAssetsToUi(currency) + AssetViewMode.NETWORKS -> walletInteractor.groupAssetsByNetwork(assets, externalBalances).mapGroupedAssetsToUi(assetIconProvider, currency) AssetViewMode.TOKENS -> walletInteractor.groupAssetsByToken(assets, externalBalances) .mapGroupedAssetsToUi( + assetIconProvider = assetIconProvider, assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt index 36e8d75d6d..2e4ccceee8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter @@ -22,7 +23,7 @@ class NetworkAssetViewHolder( fun bind(networkAsset: NetworkAssetUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { val asset = networkAsset.asset - itemAssetImage.loadTokenIcon(asset.token.configuration.iconUrl, imageLoader) + itemAssetImage.setIcon(networkAsset.icon, imageLoader) bindPriceInfo(asset) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt index 6127ea1e1d..83afa58aa1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableParentViewHolder import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem import io.novafoundation.nova.common.utils.setTextColorRes @@ -26,7 +27,7 @@ class TokenAssetGroupViewHolder( fun bind(tokenGroup: TokenGroupUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { expandableItem = tokenGroup - itemTokenGroupAssetImage.loadTokenIcon(tokenGroup.tokenIcon, imageLoader) + itemTokenGroupAssetImage.setIcon(tokenGroup.tokenIcon, imageLoader) bindPriceRate(tokenGroup) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt index 1b298b9bfa..fff22ec99b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableChildViewHolder import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon @@ -27,7 +28,7 @@ class TokenAssetViewHolder( expandableItem = tokenAsset val asset = tokenAsset.asset - itemTokenAssetImage.loadTokenIcon(asset.token.configuration.iconUrl, imageLoader) + itemTokenAssetImage.setIcon(tokenAsset.assetIcon, imageLoader) itemTokenAssetChainIcon.loadTokenIcon(tokenAsset.chain.icon, imageLoader) itemTokenAssetChainName.text = tokenAsset.chain.name diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt index 85be66a4cb..e651a0c7c3 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt @@ -2,7 +2,9 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mapper import io.novafoundation.nova.common.list.GroupedList import io.novafoundation.nova.common.list.toListWithHeaders +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance @@ -15,21 +17,28 @@ import io.novafoundation.nova.feature_currency_api.presentation.formatters.forma import java.math.BigDecimal fun GroupedList.mapGroupedAssetsToUi( + assetIconProvider: AssetIconProvider, currency: Currency, groupBalance: (NetworkAssetGroup) -> BigDecimal = NetworkAssetGroup::groupTotalBalanceFiat, balance: (AssetBalance) -> PricedAmount = AssetBalance::total, ): List { return mapKeys { (assetGroup, _) -> mapAssetGroupToUi(assetGroup, currency, groupBalance) } - .mapValues { (group, assets) -> mapAssetsToAssetModels(assets, balance) } + .mapValues { (group, assets) -> mapAssetsToAssetModels(assetIconProvider, assets, balance) } .toListWithHeaders() .filterIsInstance() } private fun mapAssetsToAssetModels( + assetIconProvider: AssetIconProvider, assets: List, balance: (AssetBalance) -> PricedAmount ): List { - return assets.map { NetworkAssetUi(mapAssetToAssetModel(it.asset, balance(it.balanceWithOffchain))) } + return assets.map { + NetworkAssetUi( + mapAssetToAssetModel(it.asset, balance(it.balanceWithOffchain)), + assetIconProvider.getAssetIcon(it.asset.token.configuration) + ) + } } fun mapAssetGroupToUi( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index 39438a2fec..b5bd313d0a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -2,10 +2,12 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mapper import io.novafoundation.nova.common.list.GroupedList import io.novafoundation.nova.common.list.toListWithHeaders +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.utils.formatTokenAmount import io.novafoundation.nova.common.utils.formatting.formatAsChange import io.novafoundation.nova.common.utils.orZero import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup @@ -17,13 +19,14 @@ import io.novafoundation.nova.feature_currency_api.presentation.formatters.forma import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel fun GroupedList.mapGroupedAssetsToUi( + assetIconProvider: AssetIconProvider, assetFilter: (groupId: String, List) -> List, groupBalance: (TokenAssetGroup) -> PricedAmount = { it.groupBalance.total }, balance: (AssetBalance) -> PricedAmount = AssetBalance::total, ): List { - return mapKeys { (group, assets) -> mapTokenAssetGroupToUi(group, assets, groupBalance) } + return mapKeys { (group, assets) -> mapTokenAssetGroupToUi(assetIconProvider, group, assets, groupBalance) } .mapValues { (group, assets) -> - val assetModels = mapAssetsToAssetModels(group, assets, balance) + val assetModels = mapAssetsToAssetModels(assetIconProvider, group, assets, balance) assetFilter(group.itemId, assetModels) } .toListWithHeaders() @@ -31,6 +34,7 @@ fun GroupedList.mapGroupedAssetsToUi( } fun mapTokenAssetGroupToUi( + assetIconProvider: AssetIconProvider, assetGroup: TokenAssetGroup, assets: List, groupBalance: (TokenAssetGroup) -> PricedAmount = { it.groupBalance.total } @@ -38,7 +42,7 @@ fun mapTokenAssetGroupToUi( val balance = groupBalance(assetGroup) return TokenGroupUi( itemId = assetGroup.groupId, - tokenIcon = assetGroup.token.icon, + tokenIcon = assetIconProvider.getAssetIcon(assetGroup.token.icon), rate = mapCoinRateChange(assetGroup.token.coinRate, assetGroup.token.currency), recentRateChange = assetGroup.token.coinRate?.recentRateChange.orZero().formatAsChange(), rateChangeColorRes = mapCoinRateChangeColorRes(assetGroup.token.coinRate), @@ -53,11 +57,19 @@ fun mapTokenAssetGroupToUi( } private fun mapAssetsToAssetModels( + assetIconProvider: AssetIconProvider, group: TokenGroupUi, assets: List, balance: (AssetBalance) -> PricedAmount ): List { - return assets.map { TokenAssetUi(group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } + return assets.map { + TokenAssetUi( + group.getId(), + mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), + assetIconProvider.getAssetIcon(it.asset.token.configuration), + mapChainToUi(it.chain) + ) + } } private fun mapType( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/AssetDetailsModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/AssetDetailsModel.kt index 438cb5c8c8..73731acf2f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/AssetDetailsModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/AssetDetailsModel.kt @@ -1,10 +1,12 @@ package io.novafoundation.nova.feature_assets.presentation.balance.detail +import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.feature_assets.presentation.model.TokenModel import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel class AssetDetailsModel( val token: TokenModel, + val assetIcon: Icon, val total: AmountModel, val transferable: AmountModel, val locked: AmountModel diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt index 0684fd9f62..5bae792337 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt @@ -10,6 +10,7 @@ import io.novafoundation.nova.common.base.BaseFragment import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.applyBarMargin import io.novafoundation.nova.common.utils.hideKeyboard +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.R @@ -120,7 +121,7 @@ class BalanceDetailFragment : BaseFragment() { } viewModel.assetDetailsModel.observe { asset -> - balanceDetailTokenIcon.loadTokenIcon(asset.token.configuration.iconUrl, imageLoader) + balanceDetailTokenIcon.setIcon(asset.assetIcon, imageLoader) balanceDetailTokenName.text = asset.token.configuration.symbol.value balanceDetailRate.text = asset.token.rate diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt index a1f48315d7..161607ecd6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt @@ -4,11 +4,13 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.Event import io.novafoundation.nova.common.utils.inBackground import io.novafoundation.nova.common.utils.sumByBigInteger import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.WalletInteractor import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor @@ -63,7 +65,8 @@ class BalanceDetailViewModel( private val currencyInteractor: CurrencyInteractor, private val controllableAssetCheck: ControllableAssetCheckMixin, private val externalBalancesInteractor: ExternalBalancesInteractor, - private val swapAvailabilityInteractor: SwapAvailabilityInteractor + private val swapAvailabilityInteractor: SwapAvailabilityInteractor, + private val assetIconProvider: AssetIconProvider ) : BaseViewModel(), TransactionHistoryUi by transactionHistoryMixin { @@ -204,7 +207,8 @@ class BalanceDetailViewModel( token = mapTokenToTokenModel(asset.token), total = mapAmountToAmountModel(asset.total + totalContributed, asset), transferable = mapAmountToAmountModel(asset.transferable, asset), - locked = mapAmountToAmountModel(asset.locked + totalContributed, asset) + locked = mapAmountToAmountModel(asset.locked + totalContributed, asset), + assetIcon = assetIconProvider.getAssetIcon(asset.token.configuration) ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/di/BalanceDetailModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/di/BalanceDetailModule.kt index 224b1b101d..801c3ab5d6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/di/BalanceDetailModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/di/BalanceDetailModule.kt @@ -9,6 +9,7 @@ import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -64,7 +65,8 @@ class BalanceDetailModule { assetPayload: AssetPayload, addressDisplayUseCase: AddressDisplayUseCase, chainRegistry: ChainRegistry, - currencyRepository: CurrencyRepository + currencyRepository: CurrencyRepository, + assetIconProvider: AssetIconProvider ): TransactionHistoryMixin { return TransactionHistoryProvider( walletInteractor = walletInteractor, @@ -76,7 +78,8 @@ class BalanceDetailModule { chainRegistry = chainRegistry, chainId = assetPayload.chainId, assetId = assetPayload.chainAssetId, - currencyRepository = currencyRepository + currencyRepository = currencyRepository, + assetIconProvider ) } @@ -96,7 +99,8 @@ class BalanceDetailModule { currencyInteractor: CurrencyInteractor, controllableAssetCheckMixin: ControllableAssetCheckMixin, externalBalancesInteractor: ExternalBalancesInteractor, - swapAvailabilityInteractor: SwapAvailabilityInteractor + swapAvailabilityInteractor: SwapAvailabilityInteractor, + assetIconProvider: AssetIconProvider ): ViewModel { return BalanceDetailViewModel( walletInteractor = walletInteractor, @@ -111,7 +115,8 @@ class BalanceDetailModule { currencyInteractor = currencyInteractor, controllableAssetCheck = controllableAssetCheckMixin, externalBalancesInteractor = externalBalancesInteractor, - swapAvailabilityInteractor = swapAvailabilityInteractor + swapAvailabilityInteractor = swapAvailabilityInteractor, + assetIconProvider = assetIconProvider ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt index bd955e79e0..8e9dc7a6b5 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt @@ -11,6 +11,7 @@ import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -57,12 +58,14 @@ class BalanceListModule { @Provides @ScreenScope fun provideAssetListMixinFactory( + assetIconProvider: AssetIconProvider, walletInteractor: WalletInteractor, assetsListInteractor: AssetsListInteractor, currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor ): AssetListMixinFactory { return AssetListMixinFactory( + assetIconProvider, walletInteractor, assetsListInteractor, currencyInteractor, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt index 5c086bec41..e5aa6c204b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkAssetUi.kt @@ -1,8 +1,9 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items +import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.runtime.ext.fullId -data class NetworkAssetUi(override val asset: AssetModel) : AssetRvItem { +data class NetworkAssetUi(override val asset: AssetModel, val icon: Icon) : AssetRvItem { override val itemId: String = "network_" + asset.token.configuration.fullId.toString() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt index 464ded3603..3c179a103e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt @@ -1,11 +1,17 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items +import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.feature_account_api.presenatation.chain.ChainUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.runtime.ext.fullId -data class TokenAssetUi(override val groupId: String, override val asset: AssetModel, val chain: ChainUi) : AssetRvItem, ExpandableChildItem { +data class TokenAssetUi( + override val groupId: String, + override val asset: AssetModel, + val assetIcon: Icon, + val chain: ChainUi +) : AssetRvItem, ExpandableChildItem { override val itemId: String = "token_" + asset.token.configuration.fullId.toString() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt index 6adbd9b5c7..b30d917195 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt @@ -1,13 +1,14 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list.model.items import androidx.annotation.ColorRes +import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel data class TokenGroupUi( override val itemId: String, - val tokenIcon: String?, + val tokenIcon: Icon, val rate: String, val recentRateChange: String, @ColorRes val rateChangeColorRes: Int, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt index 6c6fb62850..b9e2ff7993 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt @@ -1,6 +1,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.search import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.utils.inBackground import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor @@ -18,6 +19,7 @@ class AssetSearchViewModel( interactor: AssetSearchInteractor, currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor, + private val assetIconProvider: AssetIconProvider ) : BaseViewModel() { val query = MutableStateFlow("") @@ -32,7 +34,7 @@ class AssetSearchViewModel( interactor.searchAssetsFlow(query, externalBalances), selectedCurrency, ) { assets, currency -> - assets.mapGroupedAssetsToUi(currency) + assets.mapGroupedAssetsToUi(assetIconProvider, currency) } .distinctUntilChanged() .shareInBackground() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt index c85f6e372f..c8c9aaaa12 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt @@ -8,6 +8,7 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter @@ -29,13 +30,15 @@ class AssetSearchModule { router: AssetsRouter, interactor: AssetSearchInteractor, currencyInteractor: CurrencyInteractor, - externalBalancesInteractor: ExternalBalancesInteractor + externalBalancesInteractor: ExternalBalancesInteractor, + assetIconProvider: AssetIconProvider ): ViewModel { return AssetSearchViewModel( router = router, interactor = interactor, currencyInteractor = currencyInteractor, - externalBalancesInteractor = externalBalancesInteractor + externalBalancesInteractor = externalBalancesInteractor, + assetIconProvider = assetIconProvider ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt index df2c280bc6..47c0e1af03 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.buy.flow.asset +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor @@ -24,6 +25,7 @@ class AssetBuyFlowViewModel( accountUseCase: SelectedAccountUseCase, buyMixinFactory: BuyMixin.Factory, resourceManager: ResourceManager, + assetIconProvider: AssetIconProvider ) : AssetFlowViewModel( interactor, router, @@ -32,6 +34,7 @@ class AssetBuyFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, + assetIconProvider ) { val buyMixin = buyMixinFactory.create(scope = this) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt index d0c63c162e..1347155d1d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt @@ -8,6 +8,7 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor @@ -37,7 +38,8 @@ class AssetBuyFlowModule { controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, buyMixinFactory: BuyMixin.Factory, - resourceManager: ResourceManager + resourceManager: ResourceManager, + assetIconProvider: AssetIconProvider ): ViewModel { return AssetBuyFlowViewModel( interactor = interactor, @@ -47,7 +49,8 @@ class AssetBuyFlowModule { controllableAssetCheck = controllableAssetCheck, accountUseCase = accountUseCase, buyMixinFactory = buyMixinFactory, - resourceManager = resourceManager + resourceManager = resourceManager, + assetIconProvider = assetIconProvider ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index c4e9976e83..286d20be4a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -1,6 +1,7 @@ package io.novafoundation.nova.feature_assets.presentation.flow.asset import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.flowOfAll import io.novafoundation.nova.common.utils.inBackground @@ -40,6 +41,7 @@ abstract class AssetFlowViewModel( internal val accountUseCase: SelectedAccountUseCase, externalBalancesInteractor: ExternalBalancesInteractor, internal val resourceManager: ResourceManager, + private val assetIconProvider: AssetIconProvider ) : BaseViewModel() { val acknowledgeLedgerWarning = controllableAssetCheck.acknowledgeLedgerWarning @@ -82,11 +84,11 @@ abstract class AssetFlowViewModel( } open fun mapNetworkAssets(assets: Map>, currency: Currency): List { - return assets.mapGroupedAssetsToUi(currency) + return assets.mapGroupedAssetsToUi(assetIconProvider, currency) } open fun mapTokensAssets(assets: Map>): List { - return assets.map { mapTokenAssetGroupToUi(it.key, assets = it.value) } + return assets.map { mapTokenAssetGroupToUi(assetIconProvider, it.key, assets = it.value) } } internal fun validate(assetModel: AssetModel, onAccept: (AssetModel) -> Unit) { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt index 21a865ae63..9f8f20725b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt @@ -7,6 +7,7 @@ import android.view.ViewGroup import coil.ImageLoader import io.novafoundation.nova.common.base.BaseFragment import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setVisible import io.novafoundation.nova.common.view.shape.getRoundedCornerDrawable import io.novafoundation.nova.feature_account_api.presenatation.actions.setupExternalActions @@ -72,7 +73,7 @@ class ReceiveFragment : BaseFragment() { viewModel.receiver.observe { receiveFrom.setTextIcon(it.addressModel.image) - receiveFrom.primaryIcon.loadTokenIcon(it.chainAssetIcon, imageLoader) + receiveFrom.primaryIcon.setIcon(it.chainAssetIcon, imageLoader) receiveFrom.setMessage(it.addressModel.address) receiveFrom.setLabel(it.chain.name) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt index c0f8b830f1..9f40c2f599 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.Event import io.novafoundation.nova.common.utils.QrCodeGenerator @@ -17,6 +18,7 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAcco import io.novafoundation.nova.feature_account_api.domain.model.addressIn import io.novafoundation.nova.feature_account_api.presenatation.account.icon.createAddressModel import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.receive.ReceiveInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload @@ -40,6 +42,7 @@ class ReceiveViewModel( private val chainRegistry: ChainRegistry, selectedAccountUseCase: SelectedAccountUseCase, private val router: AssetsRouter, + private val assetIconProvider: AssetIconProvider ) : BaseViewModel(), ExternalActions by externalActions { private val selectedMetaAccountFlow = selectedAccountUseCase.selectedMetaAccountFlow() @@ -64,7 +67,7 @@ class ReceiveViewModel( TokenReceiver( addressModel = addressIconGenerator.createAddressModel(chain, address, AddressIconGenerator.SIZE_BIG, it.name), chain = mapChainToUi(chain), - chainAssetIcon = chainAsset.iconUrl + chainAssetIcon = assetIconProvider.getAssetIcon(chainAsset) ) } .inBackground() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt index 52d8931d6c..03c04eb825 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt @@ -11,6 +11,7 @@ import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule import io.novafoundation.nova.common.interfaces.FileProvider +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.QrCodeGenerator import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository @@ -46,6 +47,7 @@ class ReceiveModule { chainRegistry: ChainRegistry, selectedAccountUseCase: SelectedAccountUseCase, payload: AssetPayload, + assetIconProvider: AssetIconProvider ): ViewModel { return ReceiveViewModel( interactor, @@ -57,6 +59,7 @@ class ReceiveModule { chainRegistry, selectedAccountUseCase, router, + assetIconProvider ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt index 309a023e52..a53af9202d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.receive.flow.asset +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor @@ -23,6 +24,7 @@ class AssetReceiveFlowViewModel( controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, + assetIconProvider: AssetIconProvider ) : AssetFlowViewModel( interactor, router, @@ -31,6 +33,7 @@ class AssetReceiveFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, + assetIconProvider ) { override fun searchAssetsFlow(): Flow { return interactor.searchReceiveAssetsFlow(query, externalBalancesFlow) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt index b918a582c8..ca0772c392 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt @@ -8,6 +8,7 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor @@ -35,7 +36,8 @@ class AssetReceiveFlowModule { externalBalancesInteractor: ExternalBalancesInteractor, controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, - resourceManager: ResourceManager + resourceManager: ResourceManager, + assetIconProvider: AssetIconProvider ): ViewModel { return AssetReceiveFlowViewModel( interactor = interactor, @@ -44,7 +46,8 @@ class AssetReceiveFlowModule { externalBalancesInteractor = externalBalancesInteractor, controllableAssetCheck = controllableAssetCheck, accountUseCase = accountUseCase, - resourceManager = resourceManager + resourceManager = resourceManager, + assetIconProvider = assetIconProvider ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/model/TokenReceiver.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/model/TokenReceiver.kt index 71ce98ed89..a9edb9ac2a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/model/TokenReceiver.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/model/TokenReceiver.kt @@ -1,10 +1,11 @@ package io.novafoundation.nova.feature_assets.presentation.receive.model import io.novafoundation.nova.common.address.AddressModel +import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.feature_account_api.presenatation.chain.ChainUi class TokenReceiver( val addressModel: AddressModel, val chain: ChainUi, - val chainAssetIcon: String? + val chainAssetIcon: Icon ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt index 9401f1c763..5d9e60f033 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.send.flow.asset +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.view.PlaceholderModel import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -35,6 +36,7 @@ class AssetSendFlowViewModel( controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, + private val assetIconProvider: AssetIconProvider ) : AssetFlowViewModel( interactor, router, @@ -43,6 +45,7 @@ class AssetSendFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, + assetIconProvider ) { override fun searchAssetsFlow(): Flow { @@ -64,12 +67,12 @@ class AssetSendFlowViewModel( } override fun mapNetworkAssets(assets: Map>, currency: Currency): List { - return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, AssetBalance::transferable) + return assets.mapGroupedAssetsToUi(assetIconProvider, currency, NetworkAssetGroup::groupTransferableBalanceFiat, AssetBalance::transferable) } override fun mapTokensAssets(assets: Map>): List { return assets.map { (group, assets) -> - mapTokenAssetGroupToUi(group, assets = assets) { it.groupBalance.transferable } + mapTokenAssetGroupToUi(assetIconProvider, group, assets = assets) { it.groupBalance.transferable } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt index 7fdf4bb8f1..66e83a07aa 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt @@ -8,6 +8,7 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor @@ -35,7 +36,8 @@ class AssetSendFlowModule { externalBalancesInteractor: ExternalBalancesInteractor, controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, - resourceManager: ResourceManager + resourceManager: ResourceManager, + assetIconProvider: AssetIconProvider ): ViewModel { return AssetSendFlowViewModel( interactor = interactor, @@ -44,7 +46,8 @@ class AssetSendFlowModule { externalBalancesInteractor = externalBalancesInteractor, controllableAssetCheck = controllableAssetCheck, accountUseCase = accountUseCase, - resourceManager = resourceManager + resourceManager = resourceManager, + assetIconProvider = assetIconProvider ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index 63db3e3d28..fabeae84a2 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.feature_assets.presentation.swap.asset import androidx.annotation.StringRes import androidx.lifecycle.viewModelScope +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.launchUnit import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -42,7 +43,8 @@ class AssetSwapFlowViewModel( resourceManager: ResourceManager, private val swapAvailabilityInteractor: SwapAvailabilityInteractor, private val swapFlowExecutor: SwapFlowExecutor, - private val swapPayload: SwapFlowPayload + private val swapPayload: SwapFlowPayload, + private val assetIconProvider: AssetIconProvider ) : AssetFlowViewModel( interactor, router, @@ -51,6 +53,7 @@ class AssetSwapFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, + assetIconProvider ) { init { @@ -92,12 +95,12 @@ class AssetSwapFlowViewModel( } override fun mapNetworkAssets(assets: Map>, currency: Currency): List { - return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, AssetBalance::transferable) + return assets.mapGroupedAssetsToUi(assetIconProvider, currency, NetworkAssetGroup::groupTransferableBalanceFiat, AssetBalance::transferable) } override fun mapTokensAssets(assets: Map>): List { return assets.map { (group, assets) -> - mapTokenAssetGroupToUi(group, assets = assets) { it.groupBalance.transferable } + mapTokenAssetGroupToUi(assetIconProvider, group, assets = assets) { it.groupBalance.transferable } } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt index 3ee24a13bf..1ec2f3962d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt @@ -8,6 +8,7 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor @@ -41,7 +42,8 @@ class AssetSwapFlowModule { resourceManager: ResourceManager, payload: SwapFlowPayload, executorFactory: SwapFlowExecutorFactory, - swapAvailabilityInteractor: SwapAvailabilityInteractor + swapAvailabilityInteractor: SwapAvailabilityInteractor, + assetIconProvider: AssetIconProvider ): ViewModel { return AssetSwapFlowViewModel( interactor = interactor, @@ -53,7 +55,8 @@ class AssetSwapFlowModule { resourceManager = resourceManager, swapFlowExecutor = executorFactory.create(payload), swapPayload = payload, - swapAvailabilityInteractor = swapAvailabilityInteractor + swapAvailabilityInteractor = swapAvailabilityInteractor, + assetIconProvider = assetIconProvider ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt index ff3b442deb..29d3ceeb6e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt @@ -9,6 +9,7 @@ import io.novafoundation.nova.common.list.BaseListAdapter import io.novafoundation.nova.common.list.BaseViewHolder import io.novafoundation.nova.common.list.PayloadGenerator import io.novafoundation.nova.common.list.resolvePayload +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.inflateChild import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon @@ -78,7 +79,7 @@ class ManageTokensViewHolder( bindEnabled(item) - itemManageTokenMultichainIcon.loadTokenIcon(item.header.icon, imageLoader) + itemManageTokenMultichainIcon.setIcon(item.header.icon, imageLoader) itemManageTokenMultichainSymbol.text = item.header.symbol } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt index b5a6c7d457..7946aa79da 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt @@ -8,6 +8,7 @@ import androidx.core.os.bundleOf import coil.ImageLoader import io.novafoundation.nova.common.base.BaseBottomSheetFragment import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi @@ -58,7 +59,7 @@ class ManageChainTokensFragment : override fun subscribe(viewModel: ManageChainTokensViewModel) { viewModel.headerModel.observe { headerModel -> - manageChainTokenIcon.loadTokenIcon(headerModel.icon, imageLoader) + manageChainTokenIcon.setIcon(headerModel.icon, imageLoader) manageChainTokenSymbol.text = headerModel.symbol manageChainTokenSubtitle.text = headerModel.networks } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/model/MultiChainTokenModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/model/MultiChainTokenModel.kt index 9432c0a24b..1b3b497f24 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/model/MultiChainTokenModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/model/MultiChainTokenModel.kt @@ -1,7 +1,9 @@ package io.novafoundation.nova.feature_assets.presentation.tokens.manage.model +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.resources.formatListPreview +import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.tokens.manage.MultiChainToken @@ -12,19 +14,20 @@ data class MultiChainTokenModel( ) { class HeaderModel( - val icon: String?, + val icon: Icon, val symbol: String, val networks: String, ) } class MultiChainTokenMapper( + private val assetIconProvider: AssetIconProvider, private val resourceManager: ResourceManager ) { fun mapHeaderToUi(multiChainToken: MultiChainToken): MultiChainTokenModel.HeaderModel { return MultiChainTokenModel.HeaderModel( - icon = multiChainToken.icon, + icon = assetIconProvider.getAssetIcon(multiChainToken.icon), symbol = multiChainToken.symbol, networks = constructNetworksSubtitle(multiChainToken) ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/di/ExtrinsicDetailModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/di/ExtrinsicDetailModule.kt index 6d8205acbc..ea43083787 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/di/ExtrinsicDetailModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/di/ExtrinsicDetailModule.kt @@ -9,6 +9,7 @@ import dagger.multibindings.IntoMap import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.presenatation.account.AddressDisplayUseCase import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions @@ -30,6 +31,7 @@ class ExtrinsicDetailModule { operation: OperationParcelizeModel.Extrinsic, externalActions: ExternalActions.Presentation, resourceManager: ResourceManager, + assetIconProvider: AssetIconProvider ): ViewModel { return ExtrinsicDetailViewModel( addressDisplayUseCase, @@ -38,7 +40,8 @@ class ExtrinsicDetailModule { router, operation, externalActions, - resourceManager + resourceManager, + assetIconProvider ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailFragment.kt index bb18c64e30..1e7f0abada 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailFragment.kt @@ -9,6 +9,7 @@ import coil.ImageLoader import io.novafoundation.nova.common.base.BaseFragment import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.formatting.formatDateTime +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.common.utils.setTextOrHide import io.novafoundation.nova.common.view.TableCellView @@ -93,7 +94,7 @@ class ExtrinsicDetailFragment : BaseFragment() { viewModel.chainUi.observe(extrinsicDetailNetwork::showChain) viewModel.operationIcon.observe { - extrinsicDetailIcon.loadTokenIcon(it, imageLoader) + extrinsicDetailIcon.setIcon(it, imageLoader) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt index b655729a3c..2dfc929632 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.feature_assets.presentation.transaction.detail.ex import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.flowOf import io.novafoundation.nova.common.utils.inBackground @@ -28,6 +29,7 @@ class ExtrinsicDetailViewModel( val operation: OperationParcelizeModel.Extrinsic, private val externalActions: ExternalActions.Presentation, private val resourceManager: ResourceManager, + private val assetIconProvider: AssetIconProvider ) : BaseViewModel(), ExternalActions by externalActions { @@ -52,7 +54,7 @@ class ExtrinsicDetailViewModel( .share() val operationIcon = flowOf { - chainAsset().iconUrl + assetIconProvider.getAssetIcon(chainAsset().icon) }.shareInBackground() val content = flowOf { @@ -91,10 +93,12 @@ class ExtrinsicDetailViewModel( label = blockEntry.label, addressModel = getIcon(blockEntry.address), ) + is ExtrinsicContentParcel.BlockEntry.LabeledValue -> ExtrinsicContentModel.BlockEntry.LabeledValue( label = blockEntry.label, value = blockEntry.value ) + is ExtrinsicContentParcel.BlockEntry.TransactionId -> ExtrinsicContentModel.BlockEntry.TransactionId( label = resourceManager.getString(R.string.common_transaction_id), hash = blockEntry.hash diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/SwapDetailViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/SwapDetailViewModel.kt index 6530111bcf..b8a1aea05c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/SwapDetailViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/SwapDetailViewModel.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_assets.presentation.transaction.detail.sw import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.address.AddressModel import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.utils.flowOf import io.novafoundation.nova.common.utils.invoke import io.novafoundation.nova.common.utils.lazyAsync @@ -13,7 +14,7 @@ import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi import io.novafoundation.nova.feature_account_api.presenatation.account.icon.createAccountAddressModel import io.novafoundation.nova.feature_account_api.presenatation.account.wallet.WalletUiUseCase import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions -import io.novafoundation.nova.feature_account_api.presenatation.chain.icon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.model.ChainAssetWithAmountParcelModel @@ -49,6 +50,7 @@ class SwapDetailViewModel( private val walletUiUseCase: WalletUiUseCase, private val swapRateFormatter: SwapRateFormatter, private val descriptionBottomSheetLauncher: DescriptionBottomSheetLauncher, + private val assetIconProvider: AssetIconProvider, val operation: OperationParcelizeModel.Swap, ) : BaseViewModel(), ExternalActions by externalActions, @@ -152,7 +154,7 @@ class SwapDetailViewModel( income: Boolean ): SwapAssetView.Model { return SwapAssetView.Model( - assetIcon = token.configuration.icon(), + assetIcon = assetIconProvider.getAssetIcon(token.configuration), amount = mapAmountToAmountModel(amount, token, estimatedFiat = true), chainUi = mapChainToUi(chainRegistry.getChain(token.configuration.chainId)), amountTextColorRes = if (income) R.color.text_positive else R.color.text_primary diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/di/SwapDetailModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/di/SwapDetailModule.kt index fead69fb8b..bdce8bbff5 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/di/SwapDetailModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/di/SwapDetailModule.kt @@ -9,6 +9,7 @@ import dagger.multibindings.IntoMap import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.view.bottomSheet.description.DescriptionBottomSheetLauncher import io.novafoundation.nova.feature_account_api.presenatation.account.wallet.WalletUiUseCase import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions @@ -34,6 +35,7 @@ class SwapDetailModule { arbitraryTokenUseCase: ArbitraryTokenUseCase, walletUiUseCase: WalletUiUseCase, swapRateFormatter: SwapRateFormatter, + assetIconProvider: AssetIconProvider, descriptionBottomSheetLauncher: DescriptionBottomSheetLauncher ): ViewModel { return SwapDetailViewModel( @@ -45,7 +47,8 @@ class SwapDetailModule { arbitraryTokenUseCase = arbitraryTokenUseCase, walletUiUseCase = walletUiUseCase, swapRateFormatter = swapRateFormatter, - descriptionBottomSheetLauncher = descriptionBottomSheetLauncher + descriptionBottomSheetLauncher = descriptionBottomSheetLauncher, + assetIconProvider = assetIconProvider ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt index 62de34155a..9610c02a7c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt @@ -5,12 +5,14 @@ import android.text.TextUtils import android.text.style.ImageSpan import androidx.annotation.ColorRes import androidx.annotation.DrawableRes +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.buildSpannable import io.novafoundation.nova.common.utils.capitalize import io.novafoundation.nova.common.utils.images.asIcon import io.novafoundation.nova.common.utils.splitSnakeOrCamelCase import io.novafoundation.nova.feature_account_api.presenatation.account.AddressDisplayUseCase +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.model.AmountParcelModel import io.novafoundation.nova.feature_assets.presentation.model.ChainAssetWithAmountParcelModel @@ -212,6 +214,7 @@ fun mapOperationToOperationModel( operation: Operation, nameIdentifier: AddressDisplayUseCase.Identifier, resourceManager: ResourceManager, + assetIconProvider: AssetIconProvider ): OperationModel { val statusAppearance = mapStatusToStatusAppearance(operation.status) val formattedTime = resourceManager.formatTime(operation.time) @@ -273,7 +276,7 @@ fun mapOperationToOperationModel( subHeader = subHeader.value, subHeaderEllipsize = subHeader.elipsize, statusAppearance = statusAppearance, - operationIcon = operation.chainAsset.iconUrl?.asIcon() ?: R.drawable.ic_nova.asIcon() + operationIcon = assetIconProvider.getAssetIcon(operation.chainAsset) ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/TransactionHistoryProvider.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/TransactionHistoryProvider.kt index 0e2d560ddd..2aabcd9418 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/TransactionHistoryProvider.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/TransactionHistoryProvider.kt @@ -1,6 +1,7 @@ package io.novafoundation.nova.feature_assets.presentation.transaction.history.mixin import android.util.Log +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.LOG_TAG import io.novafoundation.nova.common.utils.daysFromMillis @@ -50,7 +51,8 @@ class TransactionHistoryProvider( private val chainRegistry: ChainRegistry, private val chainId: ChainId, private val assetId: Int, - private val currencyRepository: CurrencyRepository + private val currencyRepository: CurrencyRepository, + private val assetIconProvider: AssetIconProvider ) : TransactionHistoryMixin, CoroutineScope by CoroutineScope(Dispatchers.Default) { private val domainState = singleReplaySharedFlow() @@ -237,7 +239,7 @@ class TransactionHistoryProvider( val header = DayHeader(daysSinceEpoch) val operationModels = operationsPerDay.map { operation -> - mapOperationToOperationModel(chain, token, operation, accountIdentifier, resourceManager) + mapOperationToOperationModel(chain, token, operation, accountIdentifier, resourceManager, assetIconProvider) } listOf(header) + operationModels diff --git a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/di/CrowdloanFeatureDependencies.kt b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/di/CrowdloanFeatureDependencies.kt index 400677e556..d750c8a7fa 100644 --- a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/di/CrowdloanFeatureDependencies.kt +++ b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/di/CrowdloanFeatureDependencies.kt @@ -9,6 +9,7 @@ import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.secrets.v2.SecretStoreV2 import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.mixin.api.CustomDialogDisplayer +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.validation.ValidationExecutor import io.novafoundation.nova.core.storage.StorageCache @@ -36,6 +37,16 @@ import javax.inject.Named interface CrowdloanFeatureDependencies { + val parachainInfoRepository: ParachainInfoRepository + + val signerProvider: SignerProvider + + val storageStorageSharedRequestsBuilderFactory: StorageSharedRequestsBuilderFactory + + val externalBalanceDao: ExternalBalanceDao + + val assetIconProvider: AssetIconProvider + fun contributionDao(): ContributionDao fun accountUpdaterScope(): AccountUpdateScope @@ -91,12 +102,4 @@ interface CrowdloanFeatureDependencies { fun customDialogDisplayer(): CustomDialogDisplayer.Presentation fun feeLoaderMixinFactory(): FeeLoaderMixin.Factory - - val parachainInfoRepository: ParachainInfoRepository - - val signerProvider: SignerProvider - - val storageStorageSharedRequestsBuilderFactory: StorageSharedRequestsBuilderFactory - - val externalBalanceDao: ExternalBalanceDao } diff --git a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/ConfirmContributeFragment.kt b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/ConfirmContributeFragment.kt index 52d0fc69f0..a782831241 100644 --- a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/ConfirmContributeFragment.kt +++ b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/ConfirmContributeFragment.kt @@ -89,7 +89,7 @@ class ConfirmContributeFragment : BaseFragment() { viewModel.assetModelFlow.observe { confirmContributeAmount.setAssetBalance(it.assetBalance) confirmContributeAmount.setAssetName(it.tokenSymbol) - confirmContributeAmount.loadAssetImage(it.imageUrl) + confirmContributeAmount.loadAssetImage(it.icon) } confirmContributeAmount.amountInput.setText(viewModel.selectedAmount) diff --git a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/ConfirmContributeViewModel.kt b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/ConfirmContributeViewModel.kt index c580567744..13d0fdd50c 100644 --- a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/ConfirmContributeViewModel.kt +++ b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/ConfirmContributeViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.base.BaseViewModel import io.novafoundation.nova.common.mixin.api.Validatable +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.Event import io.novafoundation.nova.common.utils.flowOf @@ -43,6 +44,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch class ConfirmContributeViewModel( + private val assetIconProvider: AssetIconProvider, private val router: CrowdloanRouter, private val contributionInteractor: CrowdloanContributeInteractor, private val resourceManager: ResourceManager, @@ -72,7 +74,7 @@ class ConfirmContributeViewModel( .share() val assetModelFlow = assetFlow - .map { mapAssetToAssetModel(it, resourceManager) } + .map { mapAssetToAssetModel(assetIconProvider, it, resourceManager) } .inBackground() .share() diff --git a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/di/ConfirmContributeModule.kt b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/di/ConfirmContributeModule.kt index 8dc0a3d630..d309b4d198 100644 --- a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/di/ConfirmContributeModule.kt +++ b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/confirm/di/ConfirmContributeModule.kt @@ -9,6 +9,7 @@ import dagger.multibindings.IntoMap import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.validation.ValidationExecutor import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -30,6 +31,7 @@ class ConfirmContributeModule { @IntoMap @ViewModelKey(ConfirmContributeViewModel::class) fun provideViewModel( + assetIconProvider: AssetIconProvider, interactor: CrowdloanContributeInteractor, router: CrowdloanRouter, resourceManager: ResourceManager, @@ -44,6 +46,7 @@ class ConfirmContributeModule { singleAssetSharedState: CrowdloanSharedState, ): ViewModel { return ConfirmContributeViewModel( + assetIconProvider, router, interactor, resourceManager, diff --git a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/CrowdloanContributeFragment.kt b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/CrowdloanContributeFragment.kt index 3cb84a9615..54e6b2c4dc 100644 --- a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/CrowdloanContributeFragment.kt +++ b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/CrowdloanContributeFragment.kt @@ -96,7 +96,7 @@ class CrowdloanContributeFragment : BaseFragment() viewModel.assetModelFlow.observe { crowdloanContributeAmount.setAssetBalance(it.assetBalance) crowdloanContributeAmount.setAssetName(it.tokenSymbol) - crowdloanContributeAmount.loadAssetImage(it.imageUrl) + crowdloanContributeAmount.loadAssetImage(it.icon) } crowdloanContributeAmount.amountInput.bindTo(viewModel.enteredAmountFlow, lifecycleScope) diff --git a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/CrowdloanContributeViewModel.kt b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/CrowdloanContributeViewModel.kt index 89d25edf56..e26f2a889b 100644 --- a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/CrowdloanContributeViewModel.kt +++ b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/CrowdloanContributeViewModel.kt @@ -8,6 +8,7 @@ import io.novafoundation.nova.common.base.BaseViewModel import io.novafoundation.nova.common.mixin.api.Browserable import io.novafoundation.nova.common.mixin.api.Validatable import io.novafoundation.nova.common.mixin.api.of +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.Event import io.novafoundation.nova.common.utils.flowOf @@ -71,6 +72,7 @@ sealed class ExtraBonusState { } class CrowdloanContributeViewModel( + private val assetIconProvider: AssetIconProvider, private val router: CrowdloanRouter, private val contributionInteractor: CrowdloanContributeInteractor, private val resourceManager: ResourceManager, @@ -97,7 +99,7 @@ class CrowdloanContributeViewModel( .share() val assetModelFlow = assetFlow - .map { mapAssetToAssetModel(it, resourceManager) } + .map { mapAssetToAssetModel(assetIconProvider, it, resourceManager) } .inBackground() .share() diff --git a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/di/CrowdloanContributeModule.kt b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/di/CrowdloanContributeModule.kt index ef392ef335..19d820cce0 100644 --- a/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/di/CrowdloanContributeModule.kt +++ b/feature-crowdloan-impl/src/main/java/io/novafoundation/nova/feature_crowdloan_impl/presentation/contribute/select/di/CrowdloanContributeModule.kt @@ -8,6 +8,7 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.validation.ValidationExecutor import io.novafoundation.nova.feature_crowdloan_impl.di.customCrowdloan.CustomContributeManager @@ -27,6 +28,7 @@ class CrowdloanContributeModule { @IntoMap @ViewModelKey(CrowdloanContributeViewModel::class) fun provideViewModel( + assetIconProvider: AssetIconProvider, interactor: CrowdloanContributeInteractor, router: CrowdloanRouter, resourceManager: ResourceManager, @@ -38,6 +40,7 @@ class CrowdloanContributeModule { customContributeManager: CustomContributeManager, ): ViewModel { return CrowdloanContributeViewModel( + assetIconProvider, router, interactor, resourceManager, diff --git a/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/evm/EvmSignInteractor.kt b/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/evm/EvmSignInteractor.kt index 9d45570312..dca0ce27dc 100644 --- a/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/evm/EvmSignInteractor.kt +++ b/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/evm/EvmSignInteractor.kt @@ -311,7 +311,7 @@ class EvmSignInteractor( val chainCurrency = evmChain.nativeCurrency return Chain.Asset( - icon = evmChain.iconUrl?.let { Chain.Icon(it) }, + icon = null, id = 0, priceId = null, chainId = evmChain.chainId, diff --git a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/di/GovernanceFeatureDependencies.kt b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/di/GovernanceFeatureDependencies.kt index ab6fe593b2..3fc3d9edd1 100644 --- a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/di/GovernanceFeatureDependencies.kt +++ b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/di/GovernanceFeatureDependencies.kt @@ -11,6 +11,7 @@ import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.modules.Caching import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin import io.novafoundation.nova.common.mixin.hints.ResourcesHintsMixinFactory +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.multiResult.PartialRetriableMixin import io.novafoundation.nova.common.validation.ValidationExecutor @@ -48,6 +49,24 @@ import javax.inject.Named interface GovernanceFeatureDependencies { + val onChainIdentityRepository: OnChainIdentityRepository + + val listChooserMixinFactory: ListChooserMixin.Factory + + val identityMixinFactory: IdentityMixin.Factory + + val partialRetriableMixinFactory: PartialRetriableMixin.Factory + + val storageStorageSharedRequestsBuilderFactory: StorageSharedRequestsBuilderFactory + + val bannerVisibilityRepository: BannerVisibilityRepository + + val chainMultiLocationConverterFactory: ChainMultiLocationConverterFactory + + val assetMultiLocationConverterFactory: MultiLocationConverterFactory + + val assetIconProvider: AssetIconProvider + val feeLoaderMixinFactory: FeeLoaderMixin.Factory val validationExecutor: ValidationExecutor @@ -118,20 +137,4 @@ interface GovernanceFeatureDependencies { @Named(REMOTE_STORAGE_SOURCE) fun remoteStorageDataSource(): StorageDataSource - - val onChainIdentityRepository: OnChainIdentityRepository - - val listChooserMixinFactory: ListChooserMixin.Factory - - val identityMixinFactory: IdentityMixin.Factory - - val partialRetriableMixinFactory: PartialRetriableMixin.Factory - - val storageStorageSharedRequestsBuilderFactory: StorageSharedRequestsBuilderFactory - - val bannerVisibilityRepository: BannerVisibilityRepository - - val chainMultiLocationConverterFactory: ChainMultiLocationConverterFactory - - val assetMultiLocationConverterFactory: MultiLocationConverterFactory } diff --git a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/di/GovernanceFeatureModule.kt b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/di/GovernanceFeatureModule.kt index 6b5a05461c..01af05c6f5 100644 --- a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/di/GovernanceFeatureModule.kt +++ b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/di/GovernanceFeatureModule.kt @@ -6,6 +6,7 @@ import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.data.memory.ComputationalCache import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.FeatureScope +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.data.repository.OnChainIdentityRepository import io.novafoundation.nova.feature_account_api.domain.account.identity.IdentityProvider @@ -156,8 +157,9 @@ class GovernanceFeatureModule { @FeatureScope fun provideTracksFormatter( trackCategorizer: TrackCategorizer, - resourceManager: ResourceManager - ): TrackFormatter = RealTrackFormatter(trackCategorizer, resourceManager) + resourceManager: ResourceManager, + assetIconProvider: AssetIconProvider + ): TrackFormatter = RealTrackFormatter(trackCategorizer, resourceManager, assetIconProvider) @Provides @FeatureScope diff --git a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt index 9cecfa905e..c0bae59d97 100644 --- a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt +++ b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt @@ -1,9 +1,12 @@ package io.novafoundation.nova.feature_governance_impl.presentation.track +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.resources.formatListPreview import io.novafoundation.nova.common.utils.capitalize import io.novafoundation.nova.common.utils.images.Icon +import io.novafoundation.nova.common.utils.images.asIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_governance_api.domain.referendum.track.category.TrackType import io.novafoundation.nova.feature_governance_api.domain.track.Track import io.novafoundation.nova.feature_governance_impl.R @@ -27,70 +30,86 @@ fun TrackFormatter.formatTracks(tracks: List, asset: Chain.Asset): Tracks class RealTrackFormatter( private val trackCategorizer: TrackCategorizer, private val resourceManager: ResourceManager, + private val assetIconProvider: AssetIconProvider ) : TrackFormatter { override fun formatTrack(track: Track, asset: Chain.Asset): TrackModel { return when (trackCategorizer.typeOf(track.name)) { TrackType.ROOT -> TrackModel( name = resourceManager.getString(R.string.referendum_track_root), - icon = asset.iconUrl?.let { Icon.FromLink(it) } ?: Icon.FromDrawableRes(R.drawable.ic_block), + icon = assetIconProvider.getAssetIcon(asset, fallbackIcon = R.drawable.ic_block.asIcon()), ) + TrackType.WHITELISTED_CALLER -> TrackModel( name = resourceManager.getString(R.string.referendum_whitelisted_caller), icon = Icon.FromDrawableRes(R.drawable.ic_users), ) + TrackType.STAKING_ADMIN -> TrackModel( name = resourceManager.getString(R.string.referendum_staking_admin), icon = Icon.FromDrawableRes(R.drawable.ic_staking_filled), ) + TrackType.TREASURER -> TrackModel( name = resourceManager.getString(R.string.referendum_track_treasurer), icon = Icon.FromDrawableRes(R.drawable.ic_gem), ) + TrackType.LEASE_ADMIN -> TrackModel( name = resourceManager.getString(R.string.referendum_track_lease_admin), icon = Icon.FromDrawableRes(R.drawable.ic_governance_check_to_slot), ) + TrackType.FELLOWSHIP_ADMIN -> TrackModel( name = resourceManager.getString(R.string.referendum_track_fellowship_admin), icon = Icon.FromDrawableRes(R.drawable.ic_users), ) + TrackType.GENERAL_ADMIN -> TrackModel( name = resourceManager.getString(R.string.referendum_track_general_admin), icon = Icon.FromDrawableRes(R.drawable.ic_governance_check_to_slot), ) + TrackType.AUCTION_ADMIN -> TrackModel( name = resourceManager.getString(R.string.referendum_track_auction_admin), icon = Icon.FromDrawableRes(R.drawable.ic_rocket), ) + TrackType.REFERENDUM_CANCELLER -> TrackModel( name = resourceManager.getString(R.string.referendum_track_referendum_canceller), icon = Icon.FromDrawableRes(R.drawable.ic_governance_check_to_slot), ) + TrackType.REFERENDUM_KILLER -> TrackModel( name = resourceManager.getString(R.string.referendum_track_referendum_killer), icon = Icon.FromDrawableRes(R.drawable.ic_governance_check_to_slot), ) + TrackType.SMALL_TIPPER -> TrackModel( name = resourceManager.getString(R.string.referendum_track_small_tipper), icon = Icon.FromDrawableRes(R.drawable.ic_gem), ) + TrackType.BIG_TIPPER -> TrackModel( name = resourceManager.getString(R.string.referendum_track_big_tipper), icon = Icon.FromDrawableRes(R.drawable.ic_gem), ) + TrackType.SMALL_SPEND -> TrackModel( name = resourceManager.getString(R.string.referendum_track_small_spender), icon = Icon.FromDrawableRes(R.drawable.ic_gem), ) + TrackType.MEDIUM_SPEND -> TrackModel( name = resourceManager.getString(R.string.referendum_track_medium_spender), icon = Icon.FromDrawableRes(R.drawable.ic_gem), ) + TrackType.BIG_SPEND -> TrackModel( name = resourceManager.getString(R.string.referendum_track_big_spender), icon = Icon.FromDrawableRes(R.drawable.ic_gem), ) + TrackType.OTHER -> TrackModel( name = mapUnknownTrackNameToUi(track.name), icon = Icon.FromDrawableRes(R.drawable.ic_block), diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/di/SwapFeatureDependencies.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/di/SwapFeatureDependencies.kt index a16bd0c308..fd24d197cb 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/di/SwapFeatureDependencies.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/di/SwapFeatureDependencies.kt @@ -8,6 +8,7 @@ import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin import io.novafoundation.nova.common.mixin.hints.ResourcesHintsMixinFactory +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.validation.ValidationExecutor import io.novafoundation.nova.common.view.bottomSheet.description.DescriptionBottomSheetLauncher @@ -128,4 +129,6 @@ interface SwapFeatureDependencies { val gson: Gson val customFeeCapabilityFacade: CustomFeeCapabilityFacade + + val assetIconProvider: AssetIconProvider } diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/SwapConfirmationViewModel.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/SwapConfirmationViewModel.kt index cf3d45e4a9..4cc2e64d8b 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/SwapConfirmationViewModel.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/SwapConfirmationViewModel.kt @@ -5,6 +5,7 @@ import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.address.AddressModel import io.novafoundation.nova.common.base.BaseViewModel import io.novafoundation.nova.common.mixin.api.Validatable +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.Percent import io.novafoundation.nova.common.utils.asPercent @@ -26,7 +27,7 @@ import io.novafoundation.nova.feature_account_api.presenatation.account.wallet.W import io.novafoundation.nova.feature_account_api.presenatation.account.wallet.WalletUiUseCase import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions import io.novafoundation.nova.feature_account_api.presenatation.actions.showAddressActions -import io.novafoundation.nova.feature_account_api.presenatation.chain.icon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_swap_core.domain.model.SwapDirection import io.novafoundation.nova.feature_swap_api.domain.model.SwapFee import io.novafoundation.nova.feature_swap_api.domain.model.SwapQuote @@ -116,6 +117,7 @@ class SwapConfirmationViewModel( private val descriptionBottomSheetLauncher: DescriptionBottomSheetLauncher, private val arbitraryAssetUseCase: ArbitraryAssetUseCase, private val maxActionProviderFactory: MaxActionProviderFactory, + private val assetIconProvider: AssetIconProvider ) : BaseViewModel(), ExternalActions by externalActions, Validatable by validationExecutor, @@ -290,7 +292,7 @@ class SwapConfirmationViewModel( ): SwapAssetView.Model { val amount = formatAmount(metaAccount, chainAsset, amountInPlanks) return SwapAssetView.Model( - assetIcon = chainAsset.icon(), + assetIcon = assetIconProvider.getAssetIcon(chainAsset), amount = amount, chainUi = mapChainToUi(chain), ) diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/di/SwapConfirmationModule.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/di/SwapConfirmationModule.kt index 81af3688ca..3fd4b7de44 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/di/SwapConfirmationModule.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/di/SwapConfirmationModule.kt @@ -9,6 +9,7 @@ import dagger.multibindings.IntoMap import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.validation.ValidationExecutor import io.novafoundation.nova.common.view.bottomSheet.description.DescriptionBottomSheetLauncher @@ -56,7 +57,8 @@ class SwapConfirmationModule { feeLoaderMixinFactory: FeeLoaderMixin.Factory, descriptionBottomSheetLauncher: DescriptionBottomSheetLauncher, assetUseCase: ArbitraryAssetUseCase, - maxActionProviderFactory: MaxActionProviderFactory + maxActionProviderFactory: MaxActionProviderFactory, + assetIconProvider: AssetIconProvider ): ViewModel { return SwapConfirmationViewModel( swapRouter, @@ -78,7 +80,8 @@ class SwapConfirmationModule { feeLoaderMixinFactory, descriptionBottomSheetLauncher, assetUseCase, - maxActionProviderFactory + maxActionProviderFactory, + assetIconProvider ) } diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/di/SwapMainSettingsModule.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/di/SwapMainSettingsModule.kt index 51f0b15b37..df574276a8 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/di/SwapMainSettingsModule.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/di/SwapMainSettingsModule.kt @@ -10,6 +10,7 @@ import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.validation.ValidationExecutor import io.novafoundation.nova.common.view.bottomSheet.description.DescriptionBottomSheetLauncher @@ -41,8 +42,9 @@ class SwapMainSettingsModule { @ScreenScope fun provideSwapAmountMixinFactory( chainRegistry: ChainRegistry, - resourceManager: ResourceManager - ) = SwapAmountInputMixinFactory(chainRegistry, resourceManager) + resourceManager: ResourceManager, + assetIconProvider: AssetIconProvider + ) = SwapAmountInputMixinFactory(chainRegistry, resourceManager, assetIconProvider) @Provides @ScreenScope diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixin.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixin.kt index 092ba8275e..2f18f475bd 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixin.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixin.kt @@ -19,7 +19,7 @@ interface SwapAmountInputMixin : AmountChooserMixinBase { ) { sealed class SwapAssetIcon { - class Chosen(val assetIconUrl: String?) : SwapAssetIcon() + class Chosen(val assetIcon: Icon) : SwapAssetIcon() object NotChosen : SwapAssetIcon() } diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixinFactory.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixinFactory.kt index 628d1e8b98..d64f15daaf 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixinFactory.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixinFactory.kt @@ -1,8 +1,10 @@ package io.novafoundation.nova.feature_swap_impl.presentation.main.input import androidx.annotation.StringRes +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.validation.FieldValidator +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_account_api.presenatation.chain.iconOrFallback import io.novafoundation.nova.feature_swap_impl.R import io.novafoundation.nova.feature_swap_impl.presentation.main.input.SwapAmountInputMixin.SwapInputAssetModel @@ -19,7 +21,8 @@ import kotlinx.coroutines.flow.map class SwapAmountInputMixinFactory( private val chainRegistry: ChainRegistry, - private val resourceManager: ResourceManager + private val resourceManager: ResourceManager, + private val assetIconProvider: AssetIconProvider ) { fun create( @@ -38,7 +41,8 @@ class SwapAmountInputMixinFactory( resourceManager = resourceManager, maxActionProvider = maxActionProvider, fiatFormatter = fiatFormatter, - fieldValidator = fieldValidator + fieldValidator = fieldValidator, + assetIconProvider = assetIconProvider ) } } @@ -51,7 +55,8 @@ private class RealSwapAmountInputMixin( private val resourceManager: ResourceManager, maxActionProvider: MaxActionProvider?, fiatFormatter: AmountChooserMixinBase.FiatFormatter, - fieldValidator: FieldValidator + fieldValidator: FieldValidator, + private val assetIconProvider: AssetIconProvider ) : BaseAmountChooserProvider( coroutineScope = coroutineScope, tokenFlow = tokenFlow, @@ -75,7 +80,7 @@ private class RealSwapAmountInputMixin( val chain = chainRegistry.getChain(chainAsset.chainId) return SwapInputAssetModel( - assetIcon = SwapInputAssetModel.SwapAssetIcon.Chosen(chainAsset.iconUrl), + assetIcon = SwapInputAssetModel.SwapAssetIcon.Chosen(assetIconProvider.getAssetIcon(chainAsset)), title = chainAsset.symbol.value, subtitleIcon = chain.iconOrFallback(), subtitle = chain.name, diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt index 4a5289f6fe..e6c6d935b8 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt @@ -9,6 +9,7 @@ import coil.ImageLoader import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.WithContextExtensions import io.novafoundation.nova.common.utils.images.Icon +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.images.setIconOrMakeGone import io.novafoundation.nova.common.view.shape.getInputBackground import io.novafoundation.nova.common.view.shape.getInputBackgroundError @@ -81,7 +82,7 @@ class SwapAmountInputView @JvmOverloads constructor( private fun setAssetIcon(icon: SwapInputAssetModel.SwapAssetIcon) { return when (icon) { is SwapInputAssetModel.SwapAssetIcon.Chosen -> { - swapAmountInputImage.loadTokenIcon(icon.assetIconUrl, imageLoader) + swapAmountInputImage.setIcon(icon.assetIcon, imageLoader) swapAmountInputImage.setBackgroundResource(R.drawable.bg_token_container) } diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt index 1bf7065461..7f87ac6e0e 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt @@ -1,7 +1,9 @@ package io.novafoundation.nova.feature_wallet_api.data.mappers import androidx.annotation.StringRes +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_wallet_api.R import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.presentation.formatters.formatTokenAmount @@ -9,6 +11,7 @@ import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetModel import java.math.BigDecimal fun mapAssetToAssetModel( + assetIconProvider: AssetIconProvider, asset: Asset, resourceManager: ResourceManager, retrieveAmount: (Asset) -> BigDecimal = Asset::transferable, @@ -21,7 +24,7 @@ fun mapAssetToAssetModel( AssetModel( chainId = asset.token.configuration.chainId, chainAssetId = asset.token.configuration.id, - imageUrl = token.configuration.iconUrl, + icon = assetIconProvider.getAssetIcon(token.configuration), tokenName = token.configuration.name, tokenSymbol = token.configuration.symbol.value, assetBalance = formattedAmount diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/di/common/SelectableAssetUseCaseModule.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/di/common/SelectableAssetUseCaseModule.kt index 57c99077fe..ed7e85c500 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/di/common/SelectableAssetUseCaseModule.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/di/common/SelectableAssetUseCaseModule.kt @@ -4,6 +4,7 @@ import dagger.Binds import dagger.Module import dagger.Provides import io.novafoundation.nova.common.di.scope.FeatureScope +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_wallet_api.domain.AssetUseCase @@ -32,10 +33,12 @@ class SelectableAssetUseCaseModule { @Provides @FeatureScope fun provideAssetSelectorMixinFactory( + assetIconProvider: AssetIconProvider, assetUseCase: SelectableAssetUseCase<*>, singleAssetSharedState: SelectableSingleAssetSharedState<*>, resourceManager: ResourceManager ) = AssetSelectorFactory( + assetIconProvider, assetUseCase, singleAssetSharedState, resourceManager diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/amountChooser/AmountChooserProvider.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/amountChooser/AmountChooserProvider.kt index 764a3c289e..67fc2b642c 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/amountChooser/AmountChooserProvider.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/amountChooser/AmountChooserProvider.kt @@ -1,6 +1,7 @@ package io.novafoundation.nova.feature_wallet_api.presentation.mixin.amountChooser import androidx.annotation.StringRes +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.planksFromAmount @@ -15,7 +16,8 @@ import java.math.BigDecimal import java.math.BigInteger class AmountChooserProviderFactory( - private val resourceManager: ResourceManager + private val resourceManager: ResourceManager, + private val assetIconProvider: AssetIconProvider, ) : AmountChooserMixin.Factory { override fun create( @@ -29,6 +31,7 @@ class AmountChooserProviderFactory( usedAssetFlow = assetFlow, balanceLabel = balanceLabel, resourceManager = resourceManager, + assetIconProvider = assetIconProvider, maxActionProvider = SimpleMaxActionProvider( maxAvailableForDisplay = availableBalanceFlow, // TODO amount chooser max button @@ -56,6 +59,7 @@ class AmountChooserProvider( coroutineScope: CoroutineScope, override val usedAssetFlow: Flow, private val resourceManager: ResourceManager, + private val assetIconProvider: AssetIconProvider, @StringRes private val balanceLabel: Int?, maxActionProvider: MaxActionProvider ) : BaseAmountChooserProvider( @@ -66,7 +70,7 @@ class AmountChooserProvider( AmountChooserMixin.Presentation { override val assetModel = usedAssetFlow.map { asset -> - ChooseAmountModel(asset, resourceManager, balanceLabel) + ChooseAmountModel(asset, assetIconProvider, resourceManager, balanceLabel) } .shareInBackground() } diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/assetSelector/AssetSelectorProvider.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/assetSelector/AssetSelectorProvider.kt index 6cf92e820d..0c08903e45 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/assetSelector/AssetSelectorProvider.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/assetSelector/AssetSelectorProvider.kt @@ -1,6 +1,7 @@ package io.novafoundation.nova.feature_wallet_api.presentation.mixin.assetSelector import androidx.lifecycle.MutableLiveData +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.Event import io.novafoundation.nova.common.utils.WithCoroutineScopeExtensions @@ -20,6 +21,7 @@ import kotlinx.coroutines.launch import java.math.BigDecimal class AssetSelectorFactory( + private val assetIconProvider: AssetIconProvider, private val assetUseCase: SelectableAssetUseCase<*>, private val singleAssetSharedState: SingleAssetSharedState, private val resourceManager: ResourceManager @@ -29,11 +31,12 @@ class AssetSelectorFactory( scope: CoroutineScope, amountProvider: (Asset) -> BigDecimal ): AssetSelectorMixin.Presentation { - return AssetSelectorProvider(assetUseCase, resourceManager, singleAssetSharedState, scope, amountProvider) + return AssetSelectorProvider(assetIconProvider, assetUseCase, resourceManager, singleAssetSharedState, scope, amountProvider) } } private class AssetSelectorProvider( + private val assetIconProvider: AssetIconProvider, private val assetUseCase: SelectableAssetUseCase<*>, private val resourceManager: ResourceManager, private val singleAssetSharedState: SingleAssetSharedState, @@ -79,7 +82,7 @@ private class AssetSelectorProvider( } private fun mapAssetAndOptionToSelectorModel(assetAndOption: SelectableAssetAndOption): AssetSelectorModel { - val assetModel = mapAssetToAssetModel(assetAndOption.asset, resourceManager, patternId = null, retrieveAmount = amountProvider) + val assetModel = mapAssetToAssetModel(assetIconProvider, assetAndOption.asset, resourceManager, patternId = null, retrieveAmount = amountProvider) val title = assetAndOption.formatTitle() return AssetSelectorModel(assetModel, title, assetAndOption.option.additional.identifier) diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AssetModel.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AssetModel.kt index aff6430b9e..4a20b6396b 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AssetModel.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AssetModel.kt @@ -1,9 +1,11 @@ package io.novafoundation.nova.feature_wallet_api.presentation.model +import io.novafoundation.nova.common.utils.images.Icon + data class AssetModel( val chainId: String, val chainAssetId: Int, - val imageUrl: String?, + val icon: Icon, val tokenName: String, val tokenSymbol: String, val assetBalance: String diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/ChooseAmountModel.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/ChooseAmountModel.kt index 49b9b8a133..b46b57616e 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/ChooseAmountModel.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/ChooseAmountModel.kt @@ -1,8 +1,11 @@ package io.novafoundation.nova.feature_wallet_api.presentation.model import androidx.annotation.StringRes +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.ensureSuffix +import io.novafoundation.nova.common.utils.images.Icon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain @@ -13,19 +16,20 @@ class ChooseAmountModel( class ChooseAmountInputModel( val tokenSymbol: String, - val tokenIcon: String?, + val tokenIcon: Icon, ) internal fun ChooseAmountModel( asset: Asset, + assetIconProvider: AssetIconProvider, resourceManager: ResourceManager, @StringRes balanceLabelRes: Int?, ): ChooseAmountModel = ChooseAmountModel( - input = ChooseAmountInputModel(asset.token.configuration), + input = ChooseAmountInputModel(asset.token.configuration, assetIconProvider), balanceLabel = balanceLabelRes?.let(resourceManager::getString)?.ensureSuffix(":"), ) -internal fun ChooseAmountInputModel(chainAsset: Chain.Asset): ChooseAmountInputModel = ChooseAmountInputModel( +internal fun ChooseAmountInputModel(chainAsset: Chain.Asset, assetIconProvider: AssetIconProvider): ChooseAmountInputModel = ChooseAmountInputModel( tokenSymbol = chainAsset.symbol.value, - tokenIcon = chainAsset.iconUrl, + tokenIcon = assetIconProvider.getAssetIcon(chainAsset), ) diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt index fb069b2dc0..614907f913 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt @@ -6,6 +6,7 @@ import android.view.View import androidx.recyclerview.widget.DiffUtil import coil.ImageLoader import coil.load +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.inflateChild import io.novafoundation.nova.common.utils.setVisible import io.novafoundation.nova.common.view.bottomSheet.list.dynamic.ClickHandler @@ -57,7 +58,7 @@ private class AssetSelectorHolder( with(itemView) { itemAssetSelectorBalance.text = item.assetModel.assetBalance itemAssetSelectorTokenName.text = item.title - itemAssetSelectorIcon.load(item.assetModel.imageUrl, imageLoader) + itemAssetSelectorIcon.setIcon(item.assetModel.icon, imageLoader) itemAssetSelectorCheckmark.setVisible(isSelected, falseState = View.INVISIBLE) } } diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorView.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorView.kt index ede1dd55a5..e4386f646c 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorView.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorView.kt @@ -9,6 +9,7 @@ import coil.ImageLoader import coil.load import io.novafoundation.nova.common.utils.WithContextExtensions import io.novafoundation.nova.common.utils.getEnum +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.useAttributes import io.novafoundation.nova.common.view.shape.addRipple import io.novafoundation.nova.common.view.shape.getBlockDrawable @@ -71,7 +72,7 @@ class AssetSelectorView @JvmOverloads constructor( with(assetSelectorModel) { assetSelectorBalance.text = assetModel.assetBalance assetSelectorTokenName.text = title - assetSelectorIcon.load(assetModel.imageUrl, imageLoader) + assetSelectorIcon.setIcon(assetModel.icon, imageLoader) } } } diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt index 3dbf57cfe3..92fb7292de 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt @@ -7,9 +7,10 @@ import android.widget.EditText import androidx.constraintlayout.widget.ConstraintLayout import coil.ImageLoader import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.common.utils.images.Icon +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextOrHide import io.novafoundation.nova.common.view.shape.getInputBackground -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_wallet_api.R import io.novafoundation.nova.feature_wallet_api.presentation.model.ChooseAmountInputModel import kotlinx.android.synthetic.main.view_choose_amount_input.view.chooseAmountInputFiat @@ -38,8 +39,8 @@ class ChooseAmountInputView @JvmOverloads constructor( background = context.getInputBackground() } - fun loadAssetImage(imageUrl: String?) { - chooseAmountInputImage.loadTokenIcon(imageUrl, imageLoader) + fun loadAssetImage(icon: Icon) { + chooseAmountInputImage.setIcon(icon, imageLoader) } fun setAssetName(name: String) { diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountView.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountView.kt index 7ba63914d9..94ec888463 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountView.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountView.kt @@ -5,6 +5,7 @@ import android.util.AttributeSet import android.view.View import android.widget.EditText import androidx.constraintlayout.widget.ConstraintLayout +import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.common.utils.setTextOrHide import io.novafoundation.nova.common.utils.useAttributes import io.novafoundation.nova.feature_wallet_api.R @@ -37,8 +38,8 @@ class ChooseAmountView @JvmOverloads constructor( chooseAmountBalanceLabel.setTextOrHide(label) } - fun loadAssetImage(imageUrl: String) { - chooseAmountInput.loadAssetImage(imageUrl) + fun loadAssetImage(icon: Icon) { + chooseAmountInput.loadAssetImage(icon) } fun setTitle(title: String?) { diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt index 962ba816eb..9b0be97bd9 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt @@ -1,7 +1,7 @@ package io.novafoundation.nova.feature_wallet_impl.data.repository import com.google.gson.Gson -import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.core_db.dao.ChainAssetDao import io.novafoundation.nova.core_db.dao.SetAssetEnabledParams import io.novafoundation.nova.feature_wallet_api.domain.interfaces.ChainAssetRepository @@ -12,8 +12,7 @@ import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId class RealChainAssetRepository( private val chainAssetDao: ChainAssetDao, - private val gson: Gson, - private val assetsIconModeService: AssetsIconModeService + private val gson: Gson ) : ChainAssetRepository { override suspend fun setAssetsEnabled(enabled: Boolean, assetIds: List) { @@ -28,7 +27,6 @@ class RealChainAssetRepository( } override suspend fun getEnabledAssets(): List { - val iconMode = assetsIconModeService.getIconMode() - return chainAssetDao.getEnabledAssets().map { mapChainAssetLocalToAsset(it, gson, iconMode) } + return chainAssetDao.getEnabledAssets().map { mapChainAssetLocalToAsset(it, gson) } } } diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt index 02428e750d..4e762bb0c2 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt @@ -8,12 +8,13 @@ import io.novafoundation.nova.common.data.memory.ComputationalCache import io.novafoundation.nova.common.data.network.AppLinksProvider import io.novafoundation.nova.common.data.network.HttpExceptionHandler import io.novafoundation.nova.common.data.network.NetworkApiCreator -import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.data.storage.encrypt.EncryptedPreferences import io.novafoundation.nova.common.interfaces.FileCache import io.novafoundation.nova.common.interfaces.FileProvider import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ClipboardManager import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.QrCodeGenerator @@ -57,6 +58,36 @@ import javax.inject.Named interface WalletFeatureDependencies { + val fileCache: FileCache + + val storageCache: StorageCache + + val evmTransactionService: EvmTransactionService + + val chainAssetDao: ChainAssetDao + + val storageStorageSharedRequestsBuilderFactory: StorageSharedRequestsBuilderFactory + + val currencyRepository: CurrencyRepository + + val externalBalanceDao: ExternalBalanceDao + + val computationalCache: ComputationalCache + + val multiLocationConverterFactory: MultiLocationConverterFactory + + val extrinsicWalk: ExtrinsicWalk + + val holdsDao: HoldsDao + + val feePaymentProviderRegistry: FeePaymentProviderRegistry + + val actionAwaitableMixinFactory: ActionAwaitableMixin.Factory + + val customFeeCapabilityFacade: CustomFeeCapabilityFacade + + val assetIconProvider: AssetIconProvider + fun preferences(): Preferences fun encryptedPreferences(): EncryptedPreferences @@ -135,33 +166,6 @@ interface WalletFeatureDependencies { fun hydraDxAssetIdConverter(): HydraDxAssetIdConverter - fun assetsIconModeService(): AssetsIconModeService - - val fileCache: FileCache - - val storageCache: StorageCache - - val evmTransactionService: EvmTransactionService - - val chainAssetDao: ChainAssetDao - - val storageStorageSharedRequestsBuilderFactory: StorageSharedRequestsBuilderFactory - - val currencyRepository: CurrencyRepository - - val externalBalanceDao: ExternalBalanceDao - - val computationalCache: ComputationalCache - - val multiLocationConverterFactory: MultiLocationConverterFactory - - val extrinsicWalk: ExtrinsicWalk + fun assetsIconModeService(): AssetsIconModeRepository - val holdsDao: HoldsDao - - val feePaymentProviderRegistry: FeePaymentProviderRegistry - - val actionAwaitableMixinFactory: ActionAwaitableMixin.Factory - - val customFeeCapabilityFacade: CustomFeeCapabilityFacade } diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt index 07f4bc9659..7a516665cf 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt @@ -6,11 +6,12 @@ import dagger.Provides import io.novafoundation.nova.common.data.memory.ComputationalCache import io.novafoundation.nova.common.data.network.HttpExceptionHandler import io.novafoundation.nova.common.data.network.NetworkApiCreator -import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.FeatureScope import io.novafoundation.nova.common.interfaces.FileCache import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.core_db.dao.AssetDao import io.novafoundation.nova.core_db.dao.ChainAssetDao @@ -215,8 +216,9 @@ class WalletFeatureModule { @Provides @FeatureScope fun provideAmountChooserFactory( - resourceManager: ResourceManager - ): AmountChooserMixin.Factory = AmountChooserProviderFactory(resourceManager) + resourceManager: ResourceManager, + assetIconProvider: AssetIconProvider + ): AmountChooserMixin.Factory = AmountChooserProviderFactory(resourceManager, assetIconProvider) @Provides @FeatureScope @@ -323,9 +325,8 @@ class WalletFeatureModule { @FeatureScope fun provideChainAssetRepository( chainAssetDao: ChainAssetDao, - gson: Gson, - assetsIconModeService: AssetsIconModeService - ): ChainAssetRepository = RealChainAssetRepository(chainAssetDao, gson, assetsIconModeService) + gson: Gson + ): ChainAssetRepository = RealChainAssetRepository(chainAssetDao, gson) @Provides @FeatureScope diff --git a/runtime/build.gradle b/runtime/build.gradle index 1e96af753e..dcf08a110a 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -22,9 +22,6 @@ android { buildConfigField "String", "INFURA_API_KEY", readStringSecret("INFURA_API_KEY") buildConfigField "String", "DWELLIR_API_KEY", readStringSecret("DWELLIR_API_KEY") - - buildConfigField "String", "ASSET_COLORED_ICON_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/icons/tokens/colored/\"" - buildConfigField "String", "ASSET_WHITE_ICON_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/icons/tokens/white/\"" } buildTypes { diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt index 965c36544b..dc3a9ee67c 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt @@ -6,10 +6,11 @@ import dagger.Provides import io.novafoundation.nova.common.BuildConfig import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.network.rpc.BulkRetriever -import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.ApplicationScope import io.novafoundation.nova.common.interfaces.FileProvider +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.core_db.dao.ChainAssetDao import io.novafoundation.nova.core_db.dao.ChainDao import io.novafoundation.nova.runtime.ethereum.Web3ApiFactory @@ -229,8 +230,7 @@ class ChainRegistryModule { baseTypeSynchronizer: BaseTypeSynchronizer, runtimeSyncService: RuntimeSyncService, web3ApiPool: Web3ApiPool, - gson: Gson, - assetsIconModeService: AssetsIconModeService + gson: Gson ) = ChainRegistry( runtimeProviderPool, chainConnectionPool, @@ -241,7 +241,6 @@ class ChainRegistryModule { baseTypeSynchronizer, runtimeSyncService, web3ApiPool, - gson, - assetsIconModeService + gson ) } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeDependencies.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeDependencies.kt index c681bac045..f56a081e10 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeDependencies.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeDependencies.kt @@ -3,7 +3,7 @@ package io.novafoundation.nova.runtime.di import android.content.Context import com.google.gson.Gson import io.novafoundation.nova.common.data.network.NetworkApiCreator -import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.interfaces.FileProvider import io.novafoundation.nova.core_db.dao.ChainAssetDao @@ -31,5 +31,5 @@ interface RuntimeDependencies { fun chainAssetDao(): ChainAssetDao - fun assetsIconModeService(): AssetsIconModeService + fun assetsIconModeService(): AssetsIconModeRepository } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt index f512bb5174..dd87161fc4 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt @@ -4,7 +4,7 @@ import com.google.gson.Gson import dagger.Module import dagger.Provides import io.novafoundation.nova.common.data.network.rpc.BulkRetriever -import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.ApplicationScope import io.novafoundation.nova.core.storage.StorageCache @@ -267,12 +267,10 @@ class RuntimeModule { @Provides @ApplicationScope fun provideRemoteToDomainChainMapperFacade( - gson: Gson, - assetsIconModeService: AssetsIconModeService + gson: Gson ): RemoteToDomainChainMapperFacade { return RemoteToDomainChainMapperFacade( - gson, - assetsIconModeService + gson ) } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt index 87bb55624d..93d464b140 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt @@ -2,7 +2,6 @@ package io.novafoundation.nova.runtime.multiNetwork import android.util.Log import com.google.gson.Gson -import io.novafoundation.nova.common.data.repository.AssetsIconModeService import io.novafoundation.nova.common.utils.LOG_TAG import io.novafoundation.nova.common.utils.diffed import io.novafoundation.nova.common.utils.filterList @@ -40,7 +39,6 @@ import io.novasama.substrate_sdk_android.wsrpc.SocketService import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first @@ -64,12 +62,11 @@ class ChainRegistry( private val baseTypeSynchronizer: BaseTypeSynchronizer, private val runtimeSyncService: RuntimeSyncService, private val web3ApiPool: Web3ApiPool, - private val gson: Gson, - private val assetsIconModeService: AssetsIconModeService + private val gson: Gson ) : CoroutineScope by CoroutineScope(Dispatchers.Default) { - val currentChains = combine(chainDao.joinChainInfoFlow(), assetsIconModeService.assetsIconModeFlow()) { chains, assetIconMode -> - chains.map { mapChainLocalToChain(it, gson, assetIconMode) } + val currentChains = chainDao.joinChainInfoFlow().map { chains -> + chains.map { mapChainLocalToChain(it, gson) } } .diffed() .map { diff -> diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/DomainToLocalChainMapper.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/DomainToLocalChainMapper.kt index 29cd0b6451..595ac2d3c8 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/DomainToLocalChainMapper.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/DomainToLocalChainMapper.kt @@ -97,7 +97,7 @@ fun mapChainAssetToLocal(asset: Chain.Asset, gson: Gson): ChainAssetLocal { source = mapAssetSourceToLocal(asset.source), buyProviders = gson.toJson(asset.buyProviders), typeExtras = gson.toJson(typeExtras), - icon = asset.icon?.name, + icon = asset.icon, enabled = asset.enabled ) } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt index 186898f00a..b8c7a90ab4 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt @@ -184,7 +184,7 @@ private fun mapNodeSelectionFromLocal(nodeSelectionPreferencesLocal: NodeSelecti } } -fun mapChainLocalToChain(chainLocal: JoinedChainInfo, gson: Gson, assetIconMode: AssetIconMode): Chain { +fun mapChainLocalToChain(chainLocal: JoinedChainInfo, gson: Gson): Chain { return mapChainLocalToChain( chainLocal.chain, chainLocal.nodes, @@ -192,8 +192,7 @@ fun mapChainLocalToChain(chainLocal: JoinedChainInfo, gson: Gson, assetIconMode: chainLocal.assets, chainLocal.explorers, chainLocal.externalApis, - gson, - assetIconMode + gson ) } @@ -204,8 +203,7 @@ fun mapChainLocalToChain( assetsLocal: List, explorersLocal: List, externalApisLocal: List, - gson: Gson, - assetIconMode: AssetIconMode + gson: Gson ): Chain { val nodes = nodesLocal.sortedBy { it.orderId }.map { Chain.Node( @@ -223,7 +221,7 @@ fun mapChainLocalToChain( nodes = nodes ) - val assets = assetsLocal.map { mapChainAssetLocalToAsset(it, gson, assetIconMode) } + val assets = assetsLocal.map { mapChainAssetLocalToAsset(it, gson) } val explorers = explorersLocal.map { Chain.Explorer( @@ -278,12 +276,12 @@ fun mapChainLocalToChain( } } -fun mapChainAssetLocalToAsset(local: ChainAssetLocal, gson: Gson, assetIconMode: AssetIconMode): Chain.Asset { +fun mapChainAssetLocalToAsset(local: ChainAssetLocal, gson: Gson): Chain.Asset { val typeExtrasParsed = local.typeExtras?.let(gson::parseArbitraryObject) val buyProviders = local.buyProviders?.let?>(gson::fromJsonOrNull).orEmpty() return Chain.Asset( - icon = getAssetIconUrl(local.icon, assetIconMode), + icon = local.icon, id = local.id, symbol = local.symbol.asTokenSymbol(), precision = local.precision.asPrecision(), @@ -298,17 +296,6 @@ fun mapChainAssetLocalToAsset(local: ChainAssetLocal, gson: Gson, assetIconMode: ) } -private fun getAssetIconUrl(icon: String?, assetIconMode: AssetIconMode): Chain.Icon? { - return icon?.let { - val baseUrl = when (assetIconMode) { - AssetIconMode.COLORED -> BuildConfig.ASSET_COLORED_ICON_URL - AssetIconMode.WHITE -> BuildConfig.ASSET_WHITE_ICON_URL - } - - Chain.Icon(it, baseUrl) - } -} - private fun mapSourceFromLocal(local: ChainLocal.Source): Chain.Source { return when (local) { ChainLocal.Source.DEFAULT -> Chain.Source.DEFAULT diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt index 01e45dae0a..8f96f95377 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt @@ -1,15 +1,14 @@ package io.novafoundation.nova.runtime.multiNetwork.chain.mappers import com.google.gson.Gson -import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.core_db.model.chain.ChainLocal import io.novafoundation.nova.core_db.model.chain.NodeSelectionPreferencesLocal import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import io.novafoundation.nova.runtime.multiNetwork.chain.remote.model.ChainRemote class RemoteToDomainChainMapperFacade( - private val gson: Gson, - private val assetsIconModeService: AssetsIconModeService + private val gson: Gson ) { fun mapRemoteChainToDomain(chainRemote: ChainRemote, source: Chain.Source): Chain { @@ -30,8 +29,7 @@ class RemoteToDomainChainMapperFacade( assetsLocal = assetsLocal, explorersLocal = explorersLocal, externalApisLocal = externalApisLocal, - gson = gson, - assetsIconModeService.getIconMode() + gson = gson ) } } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/model/Chain.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/model/Chain.kt index 6ccbdbd207..f4cd220ae6 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/model/Chain.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/model/Chain.kt @@ -46,17 +46,6 @@ data class Chain( val assetsById = assets.associateBy(Asset::id) - data class Icon( - val name: String, - val baseUrl: String, - ) { - companion object; - - constructor(url: String) : this("", url) - - fun getIconUrl(): String = "$baseUrl/$name" - } - data class Additional( val defaultTip: BigInteger?, val themeColor: String?, @@ -76,7 +65,7 @@ data class Chain( ) data class Asset( - val icon: Icon?, + val icon: String?, val id: ChainAssetId, val priceId: String?, val chainId: ChainId, @@ -90,9 +79,6 @@ data class Chain( val enabled: Boolean, ) : Identifiable, Serializable { - // To support legacy code - val iconUrl = icon?.getIconUrl() - enum class Source { DEFAULT, ERC20, MANUAL } From e2b2ef259af46c3134f18b0e7b88e5766a4c3e3c Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 13:42:24 +0100 Subject: [PATCH 35/78] Fixed swap icon size and color --- .../presentation/views/SwapAmountInputView.kt | 3 +++ .../src/main/res/layout/view_swap_amount_input.xml | 1 + 2 files changed, 4 insertions(+) diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt index e6c6d935b8..512b3b4835 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt @@ -11,6 +11,7 @@ import io.novafoundation.nova.common.utils.WithContextExtensions import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.images.setIconOrMakeGone +import io.novafoundation.nova.common.utils.setImageTint import io.novafoundation.nova.common.view.shape.getInputBackground import io.novafoundation.nova.common.view.shape.getInputBackgroundError import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon @@ -82,11 +83,13 @@ class SwapAmountInputView @JvmOverloads constructor( private fun setAssetIcon(icon: SwapInputAssetModel.SwapAssetIcon) { return when (icon) { is SwapInputAssetModel.SwapAssetIcon.Chosen -> { + swapAmountInputImage.setImageTint(null) swapAmountInputImage.setIcon(icon.assetIcon, imageLoader) swapAmountInputImage.setBackgroundResource(R.drawable.bg_token_container) } SwapInputAssetModel.SwapAssetIcon.NotChosen -> { + swapAmountInputImage.setImageTint(context.getColor(R.color.icon_accent)) swapAmountInputImage.setImageResource(R.drawable.ic_add) swapAmountInputImage.setBackgroundResource(R.drawable.ic_swap_asset_default_background) } diff --git a/feature-swap-impl/src/main/res/layout/view_swap_amount_input.xml b/feature-swap-impl/src/main/res/layout/view_swap_amount_input.xml index c89b1fa759..160199a5fc 100644 --- a/feature-swap-impl/src/main/res/layout/view_swap_amount_input.xml +++ b/feature-swap-impl/src/main/res/layout/view_swap_amount_input.xml @@ -19,6 +19,7 @@ android:layout_marginStart="12dp" android:layout_marginTop="16dp" android:layout_marginBottom="16dp" + android:scaleType="centerInside" android:background="@drawable/bg_token_container" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" From 1da858b85ab72d48765e9c751e1b66e08cf4ebec Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 13:43:05 +0100 Subject: [PATCH 36/78] Run ktlint --- .../nova/feature_assets/di/AssetsFeatureDependencies.kt | 1 - .../balance/common/holders/NetworkAssetViewHolder.kt | 1 - .../balance/common/holders/TokenAssetGroupViewHolder.kt | 1 - .../presentation/balance/detail/BalanceDetailFragment.kt | 1 - .../nova/feature_assets/presentation/receive/ReceiveFragment.kt | 1 - .../presentation/tokens/manage/ManageTokensAdapter.kt | 1 - .../tokens/manage/chain/ManageChainTokensFragment.kt | 1 - .../transaction/detail/extrinsic/ExtrinsicDetailFragment.kt | 1 - .../feature_swap_impl/presentation/views/SwapAmountInputView.kt | 1 - .../presentation/view/AssetSelectorBottomSheet.kt | 1 - .../feature_wallet_api/presentation/view/AssetSelectorView.kt | 1 - .../data/repository/RealChainAssetRepository.kt | 1 - .../nova/feature_wallet_impl/di/WalletFeatureDependencies.kt | 1 - .../nova/feature_wallet_impl/di/WalletFeatureModule.kt | 1 - .../io/novafoundation/nova/runtime/di/ChainRegistryModule.kt | 2 -- .../java/io/novafoundation/nova/runtime/di/RuntimeModule.kt | 1 - .../multiNetwork/chain/mappers/LocalToDomainChainMapper.kt | 2 -- .../chain/mappers/RemoteToDomainChainMapperFacade.kt | 1 - 18 files changed, 20 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt index a1afb2e043..c418ae6e4d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt @@ -258,5 +258,4 @@ interface AssetsFeatureDependencies { fun walletConnectSessionsUseCase(): WalletConnectSessionsUseCase fun nftRepository(): NftRepository - } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt index 2e4ccceee8..272b16dfe9 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt @@ -5,7 +5,6 @@ import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextColorRes -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkAssetUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt index 83afa58aa1..d13f981843 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt @@ -7,7 +7,6 @@ import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableParentViewHolder import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem import io.novafoundation.nova.common.utils.setTextColorRes -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import kotlinx.android.synthetic.main.item_token_asset_group.view.itemAssetTokenGroupBalance diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt index 5bae792337..2c6c968608 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt @@ -12,7 +12,6 @@ import io.novafoundation.nova.common.utils.applyBarMargin import io.novafoundation.nova.common.utils.hideKeyboard import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextColorRes -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt index 9f8f20725b..fd7688f268 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt @@ -11,7 +11,6 @@ import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setVisible import io.novafoundation.nova.common.view.shape.getRoundedCornerDrawable import io.novafoundation.nova.feature_account_api.presenatation.actions.setupExternalActions -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt index 29d3ceeb6e..56d4b8f5db 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/ManageTokensAdapter.kt @@ -12,7 +12,6 @@ import io.novafoundation.nova.common.list.resolvePayload import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.inflateChild import io.novafoundation.nova.common.utils.setTextColorRes -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.tokens.manage.model.MultiChainTokenModel import kotlinx.android.synthetic.main.item_manage_token_multichain.view.itemManageTokenMultichainEnabled diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt index 7946aa79da..fc68f835a2 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt @@ -9,7 +9,6 @@ import coil.ImageLoader import io.novafoundation.nova.common.base.BaseBottomSheetFragment import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.images.setIcon -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailFragment.kt index 1e7f0abada..cb3a9b7ca6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailFragment.kt @@ -15,7 +15,6 @@ import io.novafoundation.nova.common.utils.setTextOrHide import io.novafoundation.nova.common.view.TableCellView import io.novafoundation.nova.common.view.TableView import io.novafoundation.nova.feature_account_api.presenatation.actions.setupExternalActions -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_account_api.view.showAddress import io.novafoundation.nova.feature_account_api.view.showChain import io.novafoundation.nova.feature_assets.R diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt index 512b3b4835..2362cb1a09 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt @@ -14,7 +14,6 @@ import io.novafoundation.nova.common.utils.images.setIconOrMakeGone import io.novafoundation.nova.common.utils.setImageTint import io.novafoundation.nova.common.view.shape.getInputBackground import io.novafoundation.nova.common.view.shape.getInputBackgroundError -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon import io.novafoundation.nova.feature_swap_impl.R import io.novafoundation.nova.feature_swap_impl.presentation.main.input.SwapAmountInputMixin.SwapInputAssetModel import io.novafoundation.nova.feature_wallet_api.presentation.mixin.amountChooser.AmountChooserMixinBase.AmountErrorState diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt index 614907f913..40d51d6954 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt @@ -5,7 +5,6 @@ import android.os.Bundle import android.view.View import androidx.recyclerview.widget.DiffUtil import coil.ImageLoader -import coil.load import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.inflateChild import io.novafoundation.nova.common.utils.setVisible diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorView.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorView.kt index e4386f646c..6fc4786e5f 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorView.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorView.kt @@ -6,7 +6,6 @@ import android.util.AttributeSet import android.view.View import androidx.constraintlayout.widget.ConstraintLayout import coil.ImageLoader -import coil.load import io.novafoundation.nova.common.utils.WithContextExtensions import io.novafoundation.nova.common.utils.getEnum import io.novafoundation.nova.common.utils.images.setIcon diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt index 9b0be97bd9..51fdb233f5 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/repository/RealChainAssetRepository.kt @@ -1,7 +1,6 @@ package io.novafoundation.nova.feature_wallet_impl.data.repository import com.google.gson.Gson -import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.core_db.dao.ChainAssetDao import io.novafoundation.nova.core_db.dao.SetAssetEnabledParams import io.novafoundation.nova.feature_wallet_api.domain.interfaces.ChainAssetRepository diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt index 4e762bb0c2..b1bde1f76b 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureDependencies.kt @@ -167,5 +167,4 @@ interface WalletFeatureDependencies { fun hydraDxAssetIdConverter(): HydraDxAssetIdConverter fun assetsIconModeService(): AssetsIconModeRepository - } diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt index 7a516665cf..1233a3560f 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/di/WalletFeatureModule.kt @@ -6,7 +6,6 @@ import dagger.Provides import io.novafoundation.nova.common.data.memory.ComputationalCache import io.novafoundation.nova.common.data.network.HttpExceptionHandler import io.novafoundation.nova.common.data.network.NetworkApiCreator -import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.FeatureScope import io.novafoundation.nova.common.interfaces.FileCache diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt index dc3a9ee67c..97e74a266d 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/di/ChainRegistryModule.kt @@ -6,11 +6,9 @@ import dagger.Provides import io.novafoundation.nova.common.BuildConfig import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.network.rpc.BulkRetriever -import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.ApplicationScope import io.novafoundation.nova.common.interfaces.FileProvider -import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.core_db.dao.ChainAssetDao import io.novafoundation.nova.core_db.dao.ChainDao import io.novafoundation.nova.runtime.ethereum.Web3ApiFactory diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt index dd87161fc4..6953bf5f1f 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/di/RuntimeModule.kt @@ -4,7 +4,6 @@ import com.google.gson.Gson import dagger.Module import dagger.Provides import io.novafoundation.nova.common.data.network.rpc.BulkRetriever -import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.ApplicationScope import io.novafoundation.nova.core.storage.StorageCache diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt index b8c7a90ab4..1c5c6ddab1 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/LocalToDomainChainMapper.kt @@ -2,7 +2,6 @@ package io.novafoundation.nova.runtime.multiNetwork.chain.mappers import android.util.Log import com.google.gson.Gson -import io.novafoundation.nova.common.data.model.AssetIconMode import io.novafoundation.nova.common.utils.asPrecision import io.novafoundation.nova.common.utils.asTokenSymbol import io.novafoundation.nova.common.utils.enumValueOfOrNull @@ -22,7 +21,6 @@ import io.novafoundation.nova.core_db.model.chain.ChainLocal.ConnectionStateLoca import io.novafoundation.nova.core_db.model.chain.ChainNodeLocal import io.novafoundation.nova.core_db.model.chain.JoinedChainInfo import io.novafoundation.nova.core_db.model.chain.NodeSelectionPreferencesLocal -import io.novafoundation.nova.runtime.BuildConfig import io.novafoundation.nova.runtime.multiNetwork.chain.mappers.utils.EVM_TRANSFER_PARAMETER import io.novafoundation.nova.runtime.multiNetwork.chain.mappers.utils.GovernanceReferendaParameters import io.novafoundation.nova.runtime.multiNetwork.chain.mappers.utils.SUBSTRATE_TRANSFER_PARAMETER diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt index 8f96f95377..0dcaa94782 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/chain/mappers/RemoteToDomainChainMapperFacade.kt @@ -1,7 +1,6 @@ package io.novafoundation.nova.runtime.multiNetwork.chain.mappers import com.google.gson.Gson -import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.core_db.model.chain.ChainLocal import io.novafoundation.nova.core_db.model.chain.NodeSelectionPreferencesLocal import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain From 58d6aab418f8e8d8694deff5fa710da1c69a0604 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 13:51:18 +0100 Subject: [PATCH 37/78] Clean code --- .../main/java/io/novafoundation/nova/common/di/CommonApi.kt | 4 ++-- .../novafoundation/nova/common/di/modules/CommonModule.kt | 6 +++--- .../nova/feature_assets/di/AssetsFeatureDependencies.kt | 4 ++-- .../nova/feature_assets/di/AssetsFeatureModule.kt | 4 ++-- .../domain/assets/list/AssetsListInteractor.kt | 4 ++-- .../presentation/balance/list/di/BalanceListModule.kt | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt b/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt index 359cb144d8..f148d5d495 100644 --- a/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt +++ b/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt @@ -15,7 +15,7 @@ import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser import io.novafoundation.nova.common.data.network.rpc.SocketSingleRequestExecutor import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository -import io.novafoundation.nova.common.data.repository.AssetsViewModeService +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1 import io.novafoundation.nova.common.data.secrets.v2.SecretStoreV2 @@ -187,7 +187,7 @@ interface CommonApi { fun buildTypeProvider(): BuildTypeProvider - fun assetsViewModeRepository(): AssetsViewModeService + fun assetsViewModeRepository(): AssetsViewModeRepository fun assetsIconModeService(): AssetsIconModeRepository diff --git a/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt b/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt index bd8bb0367e..7e2440a0f7 100644 --- a/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt +++ b/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt @@ -21,10 +21,10 @@ import io.novafoundation.nova.common.data.memory.ComputationalCache import io.novafoundation.nova.common.data.memory.RealComputationalCache import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository -import io.novafoundation.nova.common.data.repository.AssetsViewModeService +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.data.repository.RealAssetsIconModeRepository -import io.novafoundation.nova.common.data.repository.RealAssetsViewModeService +import io.novafoundation.nova.common.data.repository.RealAssetsViewModeRepository import io.novafoundation.nova.common.data.repository.RealBannerVisibilityRepository import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1 import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1Impl @@ -357,7 +357,7 @@ class CommonModule { @Provides @ApplicationScope - fun provideAssetsViewModeService(preferences: Preferences): AssetsViewModeService = RealAssetsViewModeService(preferences) + fun provideAssetsViewModeRepository(preferences: Preferences): AssetsViewModeRepository = RealAssetsViewModeRepository(preferences) @Provides @ApplicationScope diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt index c418ae6e4d..12f27d4abc 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt @@ -10,7 +10,7 @@ import io.novafoundation.nova.common.data.network.AppLinksProvider import io.novafoundation.nova.common.data.network.HttpExceptionHandler import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser -import io.novafoundation.nova.common.data.repository.AssetsViewModeService +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.data.storage.encrypt.EncryptedPreferences @@ -253,7 +253,7 @@ interface AssetsFeatureDependencies { fun coingeckoApi(): CoingeckoApi - fun assetsViewModeRepository(): AssetsViewModeService + fun assetsViewModeRepository(): AssetsViewModeRepository fun walletConnectSessionsUseCase(): WalletConnectSessionsUseCase diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt index 3d4bc36115..ac85f5d176 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt @@ -3,7 +3,7 @@ package io.novafoundation.nova.feature_assets.di import dagger.Module import dagger.Provides import io.novafoundation.nova.common.data.memory.ComputationalCache -import io.novafoundation.nova.common.data.repository.AssetsViewModeService +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.FeatureScope import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin @@ -70,7 +70,7 @@ class AssetsFeatureModule { @Provides @FeatureScope fun provideSearchInteractorFactory( - assetViewModeRepository: AssetsViewModeService.AssetsViewModeRepository, + assetViewModeRepository: AssetsViewModeRepository, assetSearchUseCase: AssetSearchUseCase, chainRegistry: ChainRegistry ): AssetSearchInteractorFactory = AssetViewModeAssetSearchInteractorFactory(assetViewModeRepository, assetSearchUseCase, chainRegistry) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt index 1b7aa7aac6..9ed77ae763 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt @@ -1,7 +1,7 @@ package io.novafoundation.nova.feature_assets.domain.assets.list import io.novafoundation.nova.common.data.model.AssetViewMode -import io.novafoundation.nova.common.data.repository.AssetsViewModeService +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_nft_api.data.model.Nft @@ -18,7 +18,7 @@ class AssetsListInteractor( private val accountRepository: AccountRepository, private val nftRepository: NftRepository, private val bannerVisibilityRepository: BannerVisibilityRepository, - private val assetsViewModeService: AssetsViewModeService + private val assetsViewModeService: AssetsViewModeRepository ) { fun assetsViewModeFlow() = assetsViewModeService.assetsViewModeFlow() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt index 8e9dc7a6b5..e6b06143b8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt @@ -6,7 +6,7 @@ import androidx.lifecycle.ViewModelProvider import dagger.Module import dagger.Provides import dagger.multibindings.IntoMap -import io.novafoundation.nova.common.data.repository.AssetsViewModeService +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey @@ -38,8 +38,8 @@ class BalanceListModule { accountRepository: AccountRepository, nftRepository: NftRepository, bannerVisibilityRepository: BannerVisibilityRepository, - assetsViewModeService: AssetsViewModeService - ) = AssetsListInteractor(accountRepository, nftRepository, bannerVisibilityRepository, assetsViewModeService) + assetsViewModeRepository: AssetsViewModeRepository + ) = AssetsListInteractor(accountRepository, nftRepository, bannerVisibilityRepository, assetsViewModeRepository) @Provides @ScreenScope From 310ee08c72418fab4e58bf938826faf103bbbb33 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 13:52:12 +0100 Subject: [PATCH 38/78] Run ktlint --- .../feature_assets/domain/networks/AssetNetworksInteractor.kt | 3 --- .../presentation/swap/asset/AssetSwapFlowViewModel.kt | 1 - 2 files changed, 4 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt index 688385d856..db36fa1921 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt @@ -4,7 +4,6 @@ import io.novafoundation.nova.common.utils.TokenSymbol import io.novafoundation.nova.common.utils.filterList import io.novafoundation.nova.common.utils.filterSet import io.novafoundation.nova.common.utils.flowOfAll -import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchFilter import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchUseCase import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork @@ -13,7 +12,6 @@ import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetBaseComp import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetGroupBaseComparator import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByToken import io.novafoundation.nova.feature_swap_api.domain.swap.SwapService -import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletRepository import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance import io.novafoundation.nova.feature_wallet_api.domain.model.aggregatedBalanceByAsset @@ -27,7 +25,6 @@ import io.novasama.substrate_sdk_android.hash.isPositive import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index dc3fe82f39..0f8e98a2df 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -1,6 +1,5 @@ package io.novafoundation.nova.feature_assets.presentation.swap.asset -import android.util.Log import androidx.annotation.StringRes import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.presentation.AssetIconProvider From 2d642c7dc6fa2624196b819adb87b8ce374aa9af Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 16:52:52 +0100 Subject: [PATCH 39/78] Support AssetIconProvider --- .../io/novafoundation/nova/common/view/QrCodeView.kt | 2 +- .../feature_assets/domain/receive/ReceiveInteractor.kt | 6 +++--- .../presentation/receive/ReceiveFragment.kt | 2 -- .../presentation/receive/ReceiveViewModel.kt | 10 +++++----- .../presentation/receive/di/ReceiveModule.kt | 7 +++++-- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt b/common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt index d98aaf86aa..5606c53e80 100644 --- a/common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt +++ b/common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt @@ -22,7 +22,7 @@ class QrCodeModel( val qrCode: QRCode, val overlayBackground: Drawable?, val overlayPaddingInDp: Int, - val centerOverlay: Icon?, + val centerOverlay: Icon, ) class QrCodeView @JvmOverloads constructor( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/receive/ReceiveInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/receive/ReceiveInteractor.kt index e7b9fd6427..43aa06f273 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/receive/ReceiveInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/receive/ReceiveInteractor.kt @@ -3,7 +3,7 @@ package io.novafoundation.nova.feature_assets.domain.receive import android.graphics.Bitmap import android.net.Uri import io.novafoundation.nova.common.data.model.AssetIconMode -import io.novafoundation.nova.common.data.repository.AssetsIconModeService +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.interfaces.FileProvider import io.novafoundation.nova.common.utils.write import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository @@ -18,7 +18,7 @@ class ReceiveInteractor( private val fileProvider: FileProvider, private val chainRegistry: ChainRegistry, private val accountRepository: AccountRepository, - private val assetsIconModeService: AssetsIconModeService + private val assetsIconModeRepository: AssetsIconModeRepository ) { suspend fun getQrCodeSharingString(chainId: ChainId): String = withContext(Dispatchers.Default) { @@ -28,7 +28,7 @@ class ReceiveInteractor( accountRepository.createQrAccountContent(chain, account) } - fun getAssetIconMode(): AssetIconMode = assetsIconModeService.getIconMode() + fun getAssetIconMode(): AssetIconMode = assetsIconModeRepository.getIconMode() suspend fun generateTempQrFile(qrCode: Bitmap): Result = withContext(Dispatchers.IO) { runCatching { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt index 508af193d8..85a04af92b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveFragment.kt @@ -8,10 +8,8 @@ import androidx.core.view.drawToBitmap import coil.ImageLoader import io.novafoundation.nova.common.base.BaseFragment import io.novafoundation.nova.common.di.FeatureUtils -import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.applyStatusBarInsets import io.novafoundation.nova.common.view.shape.getRoundedCornerDrawable -import io.novafoundation.nova.feature_account_api.presenatation.actions.setupExternalActions import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt index b79297d8a9..10fb46ad34 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt @@ -6,8 +6,8 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.base.BaseViewModel import io.novafoundation.nova.common.data.model.AssetIconMode -import io.novafoundation.nova.common.resources.ClipboardManager import io.novafoundation.nova.common.presentation.AssetIconProvider +import io.novafoundation.nova.common.resources.ClipboardManager import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.Event import io.novafoundation.nova.common.utils.QrCodeGenerator @@ -18,8 +18,7 @@ import io.novafoundation.nova.common.view.QrCodeModel import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_account_api.domain.model.addressIn -import io.novafoundation.nova.feature_account_api.presenatation.account.icon.createAddressModel -import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.receive.ReceiveInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload @@ -43,7 +42,8 @@ class ReceiveViewModel( private val chainRegistry: ChainRegistry, selectedAccountUseCase: SelectedAccountUseCase, private val router: AssetsRouter, - private val clipboardManager: ClipboardManager + private val clipboardManager: ClipboardManager, + private val assetIconProvider: AssetIconProvider ) : BaseViewModel() { private val selectedMetaAccountFlow = selectedAccountUseCase.selectedMetaAccountFlow() @@ -78,7 +78,7 @@ class ReceiveViewModel( qrCodeGenerator.generateQrCode(qrInput), overlayBackground, overlayPadding, - chainWithAssetAsync().asset.icon() + assetIconProvider.getAssetIcon(chainWithAssetAsync().asset) ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt index 3019506edb..022525f7e7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/di/ReceiveModule.kt @@ -11,6 +11,7 @@ import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule import io.novafoundation.nova.common.interfaces.FileProvider +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ClipboardManager import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.QrCodeGenerator @@ -45,7 +46,8 @@ class ReceiveModule { chainRegistry: ChainRegistry, selectedAccountUseCase: SelectedAccountUseCase, payload: AssetPayload, - clipboardManager: ClipboardManager + clipboardManager: ClipboardManager, + assetIconProvider: AssetIconProvider ): ViewModel { return ReceiveViewModel( interactor, @@ -55,7 +57,8 @@ class ReceiveModule { chainRegistry, selectedAccountUseCase, router, - clipboardManager + clipboardManager, + assetIconProvider ) } From 865028238ea2f461c9471e7ad651e3b01a9b02d5 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 17:00:16 +0100 Subject: [PATCH 40/78] Set asset icon as white for operations --- .../nova/common/presentation/AssetIconProvider.kt | 12 +++++++++++- .../presenatation/chain/ChainUi.kt | 4 ++++ .../transaction/history/mixin/OperationMappers.kt | 4 ++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt b/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt index 6d262086f7..0ace0a04ad 100644 --- a/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt +++ b/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt @@ -11,6 +11,8 @@ interface AssetIconProvider { val fallbackIcon: Icon fun getAssetIcon(iconName: String?, fallback: Icon = fallbackIcon): Icon + + fun getWhiteAssetIcon(iconName: String?, fallback: Icon = fallbackIcon): Icon } class RealAssetIconProvider( @@ -26,9 +28,17 @@ class RealAssetIconProvider( val iconUrl = when (assetsIconModeRepository.getIconMode()) { AssetIconMode.COLORED -> "$coloredBaseUrl/$iconName" - AssetIconMode.WHITE -> "$coloredBaseUrl/$whiteBaseUrl" + AssetIconMode.WHITE -> "$whiteBaseUrl/$iconName" } return iconUrl.asIcon() } + + override fun getWhiteAssetIcon(iconName: String?, fallback: Icon): Icon { + return if (iconName == null) { + fallback + } else { + "$whiteBaseUrl/$iconName".asIcon() + } + } } diff --git a/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt b/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt index 715f73de83..1e9856a6e1 100644 --- a/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt +++ b/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt @@ -61,3 +61,7 @@ fun chainIconFallback(): Icon { fun AssetIconProvider.getAssetIcon(asset: Chain.Asset, fallbackIcon: Icon = this.fallbackIcon): Icon { return this.getAssetIcon(asset.icon, fallbackIcon) } + +fun AssetIconProvider.getWhiteAssetIcon(asset: Chain.Asset, fallbackIcon: Icon = this.fallbackIcon): Icon { + return this.getWhiteAssetIcon(asset.icon, fallbackIcon) +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt index 9610c02a7c..f710389ff2 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt @@ -12,7 +12,7 @@ import io.novafoundation.nova.common.utils.capitalize import io.novafoundation.nova.common.utils.images.asIcon import io.novafoundation.nova.common.utils.splitSnakeOrCamelCase import io.novafoundation.nova.feature_account_api.presenatation.account.AddressDisplayUseCase -import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getWhiteAssetIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.model.AmountParcelModel import io.novafoundation.nova.feature_assets.presentation.model.ChainAssetWithAmountParcelModel @@ -276,7 +276,7 @@ fun mapOperationToOperationModel( subHeader = subHeader.value, subHeaderEllipsize = subHeader.elipsize, statusAppearance = statusAppearance, - operationIcon = assetIconProvider.getAssetIcon(operation.chainAsset) + operationIcon = assetIconProvider.getWhiteAssetIcon(operation.chainAsset) ) } From b46b64f50e4800f1f140cd76e5f29737f54a6438 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 17:20:33 +0100 Subject: [PATCH 41/78] Run ktlint --- .../feature_assets/domain/networks/AssetNetworksInteractor.kt | 3 --- .../presentation/swap/asset/AssetSwapFlowViewModel.kt | 1 - 2 files changed, 4 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt index 688385d856..db36fa1921 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/networks/AssetNetworksInteractor.kt @@ -4,7 +4,6 @@ import io.novafoundation.nova.common.utils.TokenSymbol import io.novafoundation.nova.common.utils.filterList import io.novafoundation.nova.common.utils.filterSet import io.novafoundation.nova.common.utils.flowOfAll -import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchFilter import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchUseCase import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork @@ -13,7 +12,6 @@ import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetBaseComp import io.novafoundation.nova.feature_assets.domain.common.getTokenAssetGroupBaseComparator import io.novafoundation.nova.feature_assets.domain.common.groupAndSortAssetsByToken import io.novafoundation.nova.feature_swap_api.domain.swap.SwapService -import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletRepository import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.ExternalBalance import io.novafoundation.nova.feature_wallet_api.domain.model.aggregatedBalanceByAsset @@ -27,7 +25,6 @@ import io.novasama.substrate_sdk_android.hash.isPositive import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index 0197394adb..51aa3a6f2d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -1,6 +1,5 @@ package io.novafoundation.nova.feature_assets.presentation.swap.asset -import android.util.Log import androidx.annotation.StringRes import androidx.lifecycle.viewModelScope import io.novafoundation.nova.common.resources.ResourceManager From e1d771cc921def6ddd710ccc3fd1931051d66095 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 30 Oct 2024 17:21:40 +0100 Subject: [PATCH 42/78] Fix test --- .../io/novafoundation/nova/ChainMappingIntegrationTest.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/androidTest/java/io/novafoundation/nova/ChainMappingIntegrationTest.kt b/app/src/androidTest/java/io/novafoundation/nova/ChainMappingIntegrationTest.kt index 3ae472fde7..bb0a481b88 100644 --- a/app/src/androidTest/java/io/novafoundation/nova/ChainMappingIntegrationTest.kt +++ b/app/src/androidTest/java/io/novafoundation/nova/ChainMappingIntegrationTest.kt @@ -4,7 +4,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.gson.Gson import androidx.test.platform.app.InstrumentationRegistry import dagger.Component -import io.novafoundation.nova.common.data.model.AssetIconMode import io.novafoundation.nova.common.data.network.NetworkApiCreator import io.novafoundation.nova.common.di.CommonApi import io.novafoundation.nova.common.di.FeatureContainer @@ -101,8 +100,7 @@ class ChainMappingIntegrationTest { assetsLocal = assetsLocal, explorersLocal = explorersLocal, externalApisLocal = externalApisLocal, - gson = gson, - assetIconMode = AssetIconMode.COLORED + gson = gson ) } @@ -125,8 +123,7 @@ class ChainMappingIntegrationTest { assetsLocal = assetsLocal, explorersLocal = explorersLocal, externalApisLocal = externalApisLocal, - gson = gson, - assetIconMode = AssetIconMode.COLORED + gson = gson ) } } From b227de6258422af45df9fcbb26f44220bccbc03b Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 31 Oct 2024 12:52:50 +0100 Subject: [PATCH 43/78] Appearance screen --- .../navigation/SettingsNavigationModule.kt | 4 +- .../navigation/settings/SettingsNavigator.kt | 8 ++ .../main/res/navigation/main_nav_graph.xml | 14 +++ .../repository/AssetsIconModeRepository.kt | 6 +- .../nova/common/utils/ContextExt.kt | 3 + .../res/color/appearance_selectable_text.xml | 4 + .../res/drawable/bg_appearance_container.xml | 5 + .../main/res/drawable/bg_token_container.xml | 27 ++++-- .../res/drawable/ic_settings_appearance.xml | 19 ++++ common/src/main/res/drawable/ic_token_dot.xml | 12 --- .../main/res/drawable/ic_token_dot_white.xml | 24 +++++ common/src/main/res/values/strings.xml | 5 + .../feature_settings_impl/SettingsRouter.kt | 4 + .../di/SettingsFeatureComponent.kt | 3 + .../di/SettingsFeatureDependencies.kt | 55 ++++++----- .../di/SettingsFeatureModule.kt | 9 ++ .../domain/AppearanceInteractor.kt | 23 +++++ .../assetIcons/AppearanceFragment.kt | 61 ++++++++++++ .../assetIcons/AppearanceViewModel.kt | 40 ++++++++ .../assetIcons/di/AppearanceComponent.kt | 26 +++++ .../assetIcons/di/AppearanceModule.kt | 35 +++++++ .../presentation/settings/SettingsFragment.kt | 2 + .../settings/SettingsViewModel.kt | 4 + .../main/res/layout/fragment_appearance.xml | 94 +++++++++++++++++++ .../src/main/res/layout/fragment_settings.xml | 7 ++ .../main/res/layout/item_asset_selector.xml | 2 +- 26 files changed, 446 insertions(+), 50 deletions(-) create mode 100644 common/src/main/res/color/appearance_selectable_text.xml create mode 100644 common/src/main/res/drawable/bg_appearance_container.xml create mode 100644 common/src/main/res/drawable/ic_settings_appearance.xml delete mode 100644 common/src/main/res/drawable/ic_token_dot.xml create mode 100644 common/src/main/res/drawable/ic_token_dot_white.xml create mode 100644 feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/domain/AppearanceInteractor.kt create mode 100644 feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/AppearanceFragment.kt create mode 100644 feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/AppearanceViewModel.kt create mode 100644 feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/di/AppearanceComponent.kt create mode 100644 feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/di/AppearanceModule.kt create mode 100644 feature-settings-impl/src/main/res/layout/fragment_appearance.xml diff --git a/app/src/main/java/io/novafoundation/nova/app/di/app/navigation/SettingsNavigationModule.kt b/app/src/main/java/io/novafoundation/nova/app/di/app/navigation/SettingsNavigationModule.kt index 4c2e3b2da5..6abdb481f5 100644 --- a/app/src/main/java/io/novafoundation/nova/app/di/app/navigation/SettingsNavigationModule.kt +++ b/app/src/main/java/io/novafoundation/nova/app/di/app/navigation/SettingsNavigationModule.kt @@ -5,6 +5,7 @@ import dagger.Provides import io.novafoundation.nova.app.root.navigation.NavigationHolder import io.novafoundation.nova.app.root.navigation.Navigator import io.novafoundation.nova.app.root.navigation.settings.SettingsNavigator +import io.novafoundation.nova.app.root.presentation.RootRouter import io.novafoundation.nova.common.di.scope.ApplicationScope import io.novafoundation.nova.feature_settings_impl.SettingsRouter import io.novafoundation.nova.feature_wallet_connect_impl.WalletConnectRouter @@ -15,8 +16,9 @@ class SettingsNavigationModule { @ApplicationScope @Provides fun provideRouter( + rootRouter: RootRouter, navigationHolder: NavigationHolder, walletConnectRouter: WalletConnectRouter, navigator: Navigator, - ): SettingsRouter = SettingsNavigator(navigationHolder, walletConnectRouter, navigator) + ): SettingsRouter = SettingsNavigator(navigationHolder, rootRouter, walletConnectRouter, navigator) } diff --git a/app/src/main/java/io/novafoundation/nova/app/root/navigation/settings/SettingsNavigator.kt b/app/src/main/java/io/novafoundation/nova/app/root/navigation/settings/SettingsNavigator.kt index 8291139690..92a5ac4d00 100644 --- a/app/src/main/java/io/novafoundation/nova/app/root/navigation/settings/SettingsNavigator.kt +++ b/app/src/main/java/io/novafoundation/nova/app/root/navigation/settings/SettingsNavigator.kt @@ -4,6 +4,7 @@ import io.novafoundation.nova.app.R import io.novafoundation.nova.app.root.navigation.BaseNavigator import io.novafoundation.nova.app.root.navigation.NavigationHolder import io.novafoundation.nova.app.root.navigation.Navigator +import io.novafoundation.nova.app.root.presentation.RootRouter import io.novafoundation.nova.feature_account_impl.presentation.pincode.PinCodeAction import io.novafoundation.nova.feature_account_impl.presentation.pincode.PincodeFragment import io.novafoundation.nova.feature_settings_impl.SettingsRouter @@ -19,11 +20,16 @@ import io.novafoundation.nova.feature_wallet_connect_impl.presentation.sessions. class SettingsNavigator( navigationHolder: NavigationHolder, + private val rootRouter: RootRouter, private val walletConnectDelegate: WalletConnectRouter, private val delegate: Navigator ) : BaseNavigator(navigationHolder), SettingsRouter { + override fun returnToWallet() { + rootRouter.returnToWallet() + } + override fun openWallets() { delegate.openWallets() } @@ -80,6 +86,8 @@ class SettingsNavigator( override fun openLanguages() = performNavigation(R.id.action_mainFragment_to_languagesFragment) + override fun openAppearance() = performNavigation(R.id.action_mainFragment_to_appearanceFragment) + override fun openChangePinCode() = performNavigation( actionId = R.id.action_change_pin_code, args = PincodeFragment.getPinCodeBundle(PinCodeAction.Change) diff --git a/app/src/main/res/navigation/main_nav_graph.xml b/app/src/main/res/navigation/main_nav_graph.xml index 48aff339f2..61b7ba21ca 100644 --- a/app/src/main/res/navigation/main_nav_graph.xml +++ b/app/src/main/res/navigation/main_nav_graph.xml @@ -317,6 +317,14 @@ app:popEnterAnim="@anim/fragment_close_enter" app:popExitAnim="@anim/fragment_close_exit" /> + + + + - suspend fun setAssetsIconMode(assetsViewMode: AssetIconMode) + fun setAssetsIconMode(assetsViewMode: AssetIconMode) fun getIconMode(): AssetIconMode } @@ -29,7 +27,7 @@ class RealAssetsIconModeRepository( } } - override suspend fun setAssetsIconMode(assetsViewMode: AssetIconMode) = withContext(Dispatchers.IO) { + override fun setAssetsIconMode(assetsViewMode: AssetIconMode) { preferences.putString(PREFS_ASSETS_ICON_MODE, assetsViewMode.toPrefsValue()) } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/ContextExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/ContextExt.kt index c203835eb0..3cfb48b93e 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/ContextExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/ContextExt.kt @@ -16,6 +16,7 @@ import androidx.annotation.StyleRes import androidx.core.content.ContextCompat import io.novafoundation.nova.common.R import io.novafoundation.nova.common.view.shape.addRipple +import io.novafoundation.nova.common.view.shape.getMaskedRipple import io.novafoundation.nova.common.view.shape.getRippleMask import io.novafoundation.nova.common.view.shape.getRoundedCornerDrawable import kotlin.math.roundToInt @@ -108,6 +109,8 @@ interface WithContextExtensions { val Float.dpF: Float get() = dpF(providedContext) + fun getRippleDrawable(cornerSizeInDp: Int) = providedContext.getMaskedRipple(cornerSizeInDp) + fun addRipple(to: Drawable, mask: Drawable? = getRippleMask()) = providedContext.addRipple(to, mask) fun Drawable.withRippleMask(mask: Drawable = getRippleMask()) = addRipple(this, mask) diff --git a/common/src/main/res/color/appearance_selectable_text.xml b/common/src/main/res/color/appearance_selectable_text.xml new file mode 100644 index 0000000000..0eff9797cc --- /dev/null +++ b/common/src/main/res/color/appearance_selectable_text.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/common/src/main/res/drawable/bg_appearance_container.xml b/common/src/main/res/drawable/bg_appearance_container.xml new file mode 100644 index 0000000000..35e891d176 --- /dev/null +++ b/common/src/main/res/drawable/bg_appearance_container.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/common/src/main/res/drawable/bg_token_container.xml b/common/src/main/res/drawable/bg_token_container.xml index 26cb5eb585..8953dac9b2 100644 --- a/common/src/main/res/drawable/bg_token_container.xml +++ b/common/src/main/res/drawable/bg_token_container.xml @@ -1,10 +1,25 @@ - + + + - + - + + + + + + + + + + + + + + + + + - - \ No newline at end of file diff --git a/common/src/main/res/drawable/ic_settings_appearance.xml b/common/src/main/res/drawable/ic_settings_appearance.xml new file mode 100644 index 0000000000..e9ff47a09b --- /dev/null +++ b/common/src/main/res/drawable/ic_settings_appearance.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/common/src/main/res/drawable/ic_token_dot.xml b/common/src/main/res/drawable/ic_token_dot.xml deleted file mode 100644 index 90b21487ca..0000000000 --- a/common/src/main/res/drawable/ic_token_dot.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/common/src/main/res/drawable/ic_token_dot_white.xml b/common/src/main/res/drawable/ic_token_dot_white.xml new file mode 100644 index 0000000000..d968154d4c --- /dev/null +++ b/common/src/main/res/drawable/ic_token_dot_white.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index ebda8576ce..f164206943 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -1,6 +1,11 @@ + token icons + Appearance + White + Colored + Select network for buying %s Select network for receiving %s Select network for sending %s diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/SettingsRouter.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/SettingsRouter.kt index 79bcd564fb..bdf202ca0f 100644 --- a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/SettingsRouter.kt +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/SettingsRouter.kt @@ -21,6 +21,8 @@ interface SettingsRouter : ReturnableRouter { fun openLanguages() + fun openAppearance() + fun openChangePinCode() fun openWalletDetails(metaId: Long) @@ -44,4 +46,6 @@ interface SettingsRouter : ReturnableRouter { fun finishCreateNetworkFlow() fun openEditNetwork(payload: AddNetworkPayload.Mode.Edit) + + fun returnToWallet() } diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureComponent.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureComponent.kt index da81137f48..ff4c6a00c3 100644 --- a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureComponent.kt +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureComponent.kt @@ -14,6 +14,7 @@ import io.novafoundation.nova.feature_currency_api.di.CurrencyFeatureApi import io.novafoundation.nova.feature_push_notifications.di.PushNotificationsFeatureApi import io.novafoundation.nova.feature_settings_api.SettingsFeatureApi import io.novafoundation.nova.feature_settings_impl.SettingsRouter +import io.novafoundation.nova.feature_settings_impl.presentation.assetIcons.di.AppearanceComponent import io.novafoundation.nova.feature_settings_impl.presentation.networkManagement.main.di.NetworkManagementListComponent import io.novafoundation.nova.feature_settings_impl.presentation.networkManagement.networkList.addedNetworks.di.AddedNetworkListComponent import io.novafoundation.nova.feature_settings_impl.presentation.cloudBackup.settings.di.CloudBackupSettingsComponent @@ -49,6 +50,8 @@ interface SettingsFeatureComponent : SettingsFeatureApi { fun addNetworkMainFactory(): AddNetworkMainComponent.Factory + fun appearanceFactory(): AppearanceComponent.Factory + fun addNetworkFactory(): AddNetworkComponent.Factory fun addedNetworkListFactory(): AddedNetworkListComponent.Factory diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureDependencies.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureDependencies.kt index 9811906a8b..f70795105d 100644 --- a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureDependencies.kt +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureDependencies.kt @@ -5,6 +5,7 @@ import coil.ImageLoader import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.data.network.AppLinksProvider import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin import io.novafoundation.nova.common.mixin.api.CustomDialogDisplayer @@ -41,6 +42,34 @@ import io.novafoundation.nova.feature_assets.domain.tokens.add.validations.CoinG interface SettingsFeatureDependencies { + val cloudBackupService: CloudBackupService + + val cloudBackupFacade: LocalAccountsCloudBackupFacade + + val bannerVisRepository: BannerVisibilityRepository + + val runtimeProviderPool: RuntimeProviderPool + + val nodeHealthStateTesterFactory: NodeHealthStateTesterFactory + + val chainNodeRepository: ChainNodeRepository + + val nodeConnectionFactory: NodeConnectionFactory + + val web3ApiFactory: Web3ApiFactory + + val validationExecutor: ValidationExecutor + + val preConfiguredChainsRepository: PreConfiguredChainsRepository + + val coinGeckoLinkParser: CoinGeckoLinkParser + + val chainRepository: ChainRepository + + val coinGeckoLinkValidationFactory: CoinGeckoLinkValidationFactory + + val assetsIconModeRepository: AssetsIconModeRepository + val accountRepository: AccountRepository val accountInteractor: AccountInteractor @@ -90,30 +119,4 @@ interface SettingsFeatureDependencies { fun customDialogProvider(): CustomDialogDisplayer.Presentation fun context(): Context - - val cloudBackupService: CloudBackupService - - val cloudBackupFacade: LocalAccountsCloudBackupFacade - - val bannerVisRepository: BannerVisibilityRepository - - val runtimeProviderPool: RuntimeProviderPool - - val nodeHealthStateTesterFactory: NodeHealthStateTesterFactory - - val chainNodeRepository: ChainNodeRepository - - val nodeConnectionFactory: NodeConnectionFactory - - val web3ApiFactory: Web3ApiFactory - - val validationExecutor: ValidationExecutor - - val preConfiguredChainsRepository: PreConfiguredChainsRepository - - val coinGeckoLinkParser: CoinGeckoLinkParser - - val chainRepository: ChainRepository - - val coinGeckoLinkValidationFactory: CoinGeckoLinkValidationFactory } diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureModule.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureModule.kt index d13c099193..6b28041134 100644 --- a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureModule.kt +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/di/SettingsFeatureModule.kt @@ -8,6 +8,7 @@ import io.novafoundation.nova.feature_settings_impl.domain.CloudBackupSettingsIn import io.novafoundation.nova.feature_settings_impl.domain.RealCloudBackupSettingsInteractor import dagger.Provides import io.novafoundation.nova.common.data.network.coingecko.CoinGeckoLinkParser +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.di.scope.FeatureScope import io.novafoundation.nova.common.resources.ResourceManager @@ -15,11 +16,13 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountInter import io.novafoundation.nova.feature_assets.domain.tokens.add.validations.CoinGeckoLinkValidationFactory import io.novafoundation.nova.feature_settings_impl.data.NodeChainIdRepositoryFactory import io.novafoundation.nova.feature_settings_impl.domain.AddNetworkInteractor +import io.novafoundation.nova.feature_settings_impl.domain.AppearanceInteractor import io.novafoundation.nova.feature_settings_impl.domain.CustomNodeInteractor import io.novafoundation.nova.feature_settings_impl.domain.NetworkManagementChainInteractor import io.novafoundation.nova.feature_settings_impl.domain.NetworkManagementInteractor import io.novafoundation.nova.feature_settings_impl.domain.PreConfiguredNetworksInteractor import io.novafoundation.nova.feature_settings_impl.domain.RealAddNetworkInteractor +import io.novafoundation.nova.feature_settings_impl.domain.RealAppearanceInteractor import io.novafoundation.nova.feature_settings_impl.domain.RealCustomNodeInteractor import io.novafoundation.nova.feature_settings_impl.domain.RealNetworkManagementChainInteractor import io.novafoundation.nova.feature_settings_impl.domain.RealNetworkManagementInteractor @@ -169,4 +172,10 @@ class SettingsFeatureModule { customChainFactory ) } + + @Provides + @FeatureScope + fun provideAppearanceInteractor(assetsIconModeRepository: AssetsIconModeRepository): AppearanceInteractor { + return RealAppearanceInteractor(assetsIconModeRepository) + } } diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/domain/AppearanceInteractor.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/domain/AppearanceInteractor.kt new file mode 100644 index 0000000000..50e0896fb0 --- /dev/null +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/domain/AppearanceInteractor.kt @@ -0,0 +1,23 @@ +package io.novafoundation.nova.feature_settings_impl.domain + +import io.novafoundation.nova.common.data.model.AssetIconMode +import io.novafoundation.nova.common.data.repository.AssetsIconModeRepository +import kotlinx.coroutines.flow.Flow + +interface AppearanceInteractor { + + fun assetIconModeFlow(): Flow + + fun setIconMode(iconMode: AssetIconMode) +} + +class RealAppearanceInteractor( + private val assetsIconModeRepository: AssetsIconModeRepository +) : AppearanceInteractor { + + override fun assetIconModeFlow() = assetsIconModeRepository.assetsIconModeFlow() + + override fun setIconMode(iconMode: AssetIconMode) { + assetsIconModeRepository.setAssetsIconMode(iconMode) + } +} diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/AppearanceFragment.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/AppearanceFragment.kt new file mode 100644 index 0000000000..c1312c3918 --- /dev/null +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/AppearanceFragment.kt @@ -0,0 +1,61 @@ +package io.novafoundation.nova.feature_settings_impl.presentation.assetIcons + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import io.novafoundation.nova.common.base.BaseFragment +import io.novafoundation.nova.common.di.FeatureUtils +import io.novafoundation.nova.common.utils.applyStatusBarInsets +import io.novafoundation.nova.feature_settings_api.SettingsFeatureApi +import io.novafoundation.nova.feature_settings_impl.R +import io.novafoundation.nova.feature_settings_impl.di.SettingsFeatureComponent +import kotlinx.android.synthetic.main.fragment_appearance.appearanceColoredButton +import kotlinx.android.synthetic.main.fragment_appearance.appearanceColoredIcon +import kotlinx.android.synthetic.main.fragment_appearance.appearanceColoredText +import kotlinx.android.synthetic.main.fragment_appearance.appearanceToolbar +import kotlinx.android.synthetic.main.fragment_appearance.appearanceWhiteButton +import kotlinx.android.synthetic.main.fragment_appearance.appearanceWhiteIcon +import kotlinx.android.synthetic.main.fragment_appearance.appearanceWhiteText + +class AppearanceFragment : BaseFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View? { + return inflater.inflate(R.layout.fragment_appearance, container, false) + } + + override fun initViews() { + appearanceToolbar.applyStatusBarInsets() + appearanceToolbar.setHomeButtonListener { viewModel.backClicked() } + + appearanceWhiteButton.setOnClickListener { viewModel.selectWhiteIcon() } + appearanceColoredButton.setOnClickListener { viewModel.selectColoredIcon() } + + appearanceWhiteButton.background = getRippleDrawable(cornerSizeInDp = 10) + appearanceColoredButton.background = getRippleDrawable(cornerSizeInDp = 10) + } + + override fun inject() { + FeatureUtils.getFeature( + requireContext(), + SettingsFeatureApi::class.java + ) + .appearanceFactory() + .create(this) + .inject(this) + } + + override fun subscribe(viewModel: AppearanceViewModel) { + viewModel.assetIconsStateFlow.observe { + appearanceWhiteIcon.isSelected = it.whiteActive + appearanceWhiteText.isSelected = it.whiteActive + + appearanceColoredIcon.isSelected = it.coloredActive + appearanceColoredText.isSelected = it.coloredActive + } + } +} diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/AppearanceViewModel.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/AppearanceViewModel.kt new file mode 100644 index 0000000000..9f2c39e946 --- /dev/null +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/AppearanceViewModel.kt @@ -0,0 +1,40 @@ +package io.novafoundation.nova.feature_settings_impl.presentation.assetIcons + +import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.data.model.AssetIconMode +import io.novafoundation.nova.feature_settings_impl.SettingsRouter +import io.novafoundation.nova.feature_settings_impl.domain.AppearanceInteractor +import kotlinx.coroutines.flow.map + +class AssetIconsStateModel( + val whiteActive: Boolean, + val coloredActive: Boolean +) + +class AppearanceViewModel( + private val interactor: AppearanceInteractor, + private val router: SettingsRouter +) : BaseViewModel() { + + val assetIconsStateFlow = interactor.assetIconModeFlow() + .map { + AssetIconsStateModel( + whiteActive = it == AssetIconMode.WHITE, + coloredActive = it == AssetIconMode.COLORED + ) + } + + fun selectWhiteIcon() { + interactor.setIconMode(AssetIconMode.WHITE) + router.returnToWallet() + } + + fun selectColoredIcon() { + interactor.setIconMode(AssetIconMode.COLORED) + router.returnToWallet() + } + + fun backClicked() { + router.back() + } +} diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/di/AppearanceComponent.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/di/AppearanceComponent.kt new file mode 100644 index 0000000000..643bca793f --- /dev/null +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/di/AppearanceComponent.kt @@ -0,0 +1,26 @@ +package io.novafoundation.nova.feature_settings_impl.presentation.assetIcons.di + +import androidx.fragment.app.Fragment +import dagger.BindsInstance +import dagger.Subcomponent +import io.novafoundation.nova.common.di.scope.ScreenScope +import io.novafoundation.nova.feature_settings_impl.presentation.assetIcons.AppearanceFragment + +@Subcomponent( + modules = [ + AppearanceModule::class + ] +) +@ScreenScope +interface AppearanceComponent { + + @Subcomponent.Factory + interface Factory { + + fun create( + @BindsInstance fragment: Fragment + ): AppearanceComponent + } + + fun inject(fragment: AppearanceFragment) +} diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/di/AppearanceModule.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/di/AppearanceModule.kt new file mode 100644 index 0000000000..09f54feda4 --- /dev/null +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/assetIcons/di/AppearanceModule.kt @@ -0,0 +1,35 @@ +package io.novafoundation.nova.feature_settings_impl.presentation.assetIcons.di + +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import dagger.Module +import dagger.Provides +import dagger.multibindings.IntoMap +import io.novafoundation.nova.common.di.viewmodel.ViewModelKey +import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.feature_settings_impl.SettingsRouter +import io.novafoundation.nova.feature_settings_impl.domain.AppearanceInteractor +import io.novafoundation.nova.feature_settings_impl.presentation.assetIcons.AppearanceViewModel + +@Module(includes = [ViewModelModule::class]) +class AppearanceModule { + + @Provides + @IntoMap + @ViewModelKey(AppearanceViewModel::class) + fun provideViewModel( + interactor: AppearanceInteractor, + router: SettingsRouter + ): ViewModel { + return AppearanceViewModel( + interactor, + router + ) + } + + @Provides + fun provideViewModelCreator(fragment: Fragment, viewModelFactory: ViewModelProvider.Factory): AppearanceViewModel { + return ViewModelProvider(fragment, viewModelFactory).get(AppearanceViewModel::class.java) + } +} diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/settings/SettingsFragment.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/settings/SettingsFragment.kt index a1d8dac621..d0be400b66 100644 --- a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/settings/SettingsFragment.kt +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/settings/SettingsFragment.kt @@ -19,6 +19,7 @@ import io.novafoundation.nova.feature_settings_impl.R import io.novafoundation.nova.feature_settings_impl.di.SettingsFeatureComponent import kotlinx.android.synthetic.main.fragment_settings.accountView import kotlinx.android.synthetic.main.fragment_settings.settingsAppVersion +import kotlinx.android.synthetic.main.fragment_settings.settingsAppearance import kotlinx.android.synthetic.main.fragment_settings.settingsAvatar import kotlinx.android.synthetic.main.fragment_settings.settingsBiometricAuth import kotlinx.android.synthetic.main.fragment_settings.settingsCloudBackup @@ -63,6 +64,7 @@ class SettingsFragment : BaseFragment() { settingsPushNotifications.setOnClickListener { viewModel.pushNotificationsClicked() } settingsCurrency.setOnClickListener { viewModel.currenciesClicked() } settingsLanguage.setOnClickListener { viewModel.languagesClicked() } + settingsAppearance.setOnClickListener { viewModel.appearanceClicked() } settingsTelegram.setOnClickListener { viewModel.telegramClicked() } settingsTwitter.setOnClickListener { viewModel.twitterClicked() } diff --git a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/settings/SettingsViewModel.kt b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/settings/SettingsViewModel.kt index 687b88dc25..ef9ac5f90d 100644 --- a/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/settings/SettingsViewModel.kt +++ b/feature-settings-impl/src/main/java/io/novafoundation/nova/feature_settings_impl/presentation/settings/SettingsViewModel.kt @@ -144,6 +144,10 @@ class SettingsViewModel( router.openLanguages() } + fun appearanceClicked() { + router.openAppearance() + } + fun changeBiometricAuth() { launch { if (biometricService.isEnabled()) { diff --git a/feature-settings-impl/src/main/res/layout/fragment_appearance.xml b/feature-settings-impl/src/main/res/layout/fragment_appearance.xml new file mode 100644 index 0000000000..79ff49bfd3 --- /dev/null +++ b/feature-settings-impl/src/main/res/layout/fragment_appearance.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/feature-settings-impl/src/main/res/layout/fragment_settings.xml b/feature-settings-impl/src/main/res/layout/fragment_settings.xml index 110b3b98b1..86dd39fc8e 100644 --- a/feature-settings-impl/src/main/res/layout/fragment_settings.xml +++ b/feature-settings-impl/src/main/res/layout/fragment_settings.xml @@ -110,6 +110,13 @@ app:title="@string/language_title" tools:settingValue="English" /> + + + tools:src="@drawable/ic_token_dot_white" /> Date: Fri, 1 Nov 2024 10:11:30 +0100 Subject: [PATCH 44/78] Fixed pr notes --- .../common/presentation/AssetIconProvider.kt | 37 ++++++++++++------- .../presenatation/chain/ChainUi.kt | 11 ++++-- .../assets/list/AssetsListInteractor.kt | 6 +-- .../common/mappers/NetworkAssetMappers.kt | 4 +- .../common/mappers/TokenAssetMappers.kt | 7 ++-- .../balance/detail/BalanceDetailViewModel.kt | 4 +- .../presentation/receive/ReceiveViewModel.kt | 4 +- .../manage/model/MultiChainTokenModel.kt | 3 +- .../extrinsic/ExtrinsicDetailViewModel.kt | 3 +- .../detail/swap/SwapDetailViewModel.kt | 4 +- .../history/mixin/OperationMappers.kt | 6 ++- .../presentation/track/TrackFormatter.kt | 4 +- .../confirmation/SwapConfirmationViewModel.kt | 4 +- .../main/input/SwapAmountInputMixinFactory.kt | 4 +- .../feature_wallet_api/data/mappers/Asset.kt | 4 +- .../presentation/model/ChooseAmountModel.kt | 4 +- .../runtime/multiNetwork/ChainRegistry.kt | 6 +-- 17 files changed, 67 insertions(+), 48 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt b/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt index 0ace0a04ad..2a1fe45762 100644 --- a/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt +++ b/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt @@ -8,11 +8,11 @@ import io.novafoundation.nova.common.utils.images.asIcon interface AssetIconProvider { - val fallbackIcon: Icon + companion object; - fun getAssetIcon(iconName: String?, fallback: Icon = fallbackIcon): Icon + fun getAssetIconOrFallback(iconName: String): Icon - fun getWhiteAssetIcon(iconName: String?, fallback: Icon = fallbackIcon): Icon + fun getAssetIconOrFallback(iconName: String, iconMode: AssetIconMode): Icon } class RealAssetIconProvider( @@ -21,11 +21,12 @@ class RealAssetIconProvider( private val whiteBaseUrl: String ) : AssetIconProvider { - override val fallbackIcon: Icon = R.drawable.ic_nova.asIcon() - override fun getAssetIcon(iconName: String?, fallback: Icon): Icon { - if (iconName == null) return fallback + override fun getAssetIconOrFallback(iconName: String): Icon { + return getAssetIconOrFallback(iconName, assetsIconModeRepository.getIconMode()) + } + override fun getAssetIconOrFallback(iconName: String, iconMode: AssetIconMode): Icon { val iconUrl = when (assetsIconModeRepository.getIconMode()) { AssetIconMode.COLORED -> "$coloredBaseUrl/$iconName" AssetIconMode.WHITE -> "$whiteBaseUrl/$iconName" @@ -33,12 +34,22 @@ class RealAssetIconProvider( return iconUrl.asIcon() } +} - override fun getWhiteAssetIcon(iconName: String?, fallback: Icon): Icon { - return if (iconName == null) { - fallback - } else { - "$whiteBaseUrl/$iconName".asIcon() - } - } +val AssetIconProvider.Companion.fallbackIcon: Icon + get() = R.drawable.ic_nova.asIcon() + +fun AssetIconProvider.getAssetIconOrFallback( + iconName: String?, + fallback: Icon = AssetIconProvider.fallbackIcon +): Icon { + return iconName?.let { getAssetIconOrFallback(it) } ?: fallback +} + +fun AssetIconProvider.getAssetIconOrFallback( + iconName: String?, + iconMode: AssetIconMode, + fallback: Icon = AssetIconProvider.fallbackIcon +): Icon { + return iconName?.let { getAssetIconOrFallback(it, iconMode) } ?: fallback } diff --git a/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt b/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt index 1e9856a6e1..7e38f07a7d 100644 --- a/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt +++ b/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt @@ -6,7 +6,10 @@ import android.widget.ImageView import coil.ImageLoader import coil.load import coil.request.ImageRequest +import io.novafoundation.nova.common.data.model.AssetIconMode import io.novafoundation.nova.common.presentation.AssetIconProvider +import io.novafoundation.nova.common.presentation.fallbackIcon +import io.novafoundation.nova.common.presentation.getAssetIconOrFallback import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.common.utils.images.asIcon import io.novafoundation.nova.feature_account_api.R @@ -58,10 +61,10 @@ fun chainIconFallback(): Icon { return R.drawable.ic_fallback_network_icon.asIcon() } -fun AssetIconProvider.getAssetIcon(asset: Chain.Asset, fallbackIcon: Icon = this.fallbackIcon): Icon { - return this.getAssetIcon(asset.icon, fallbackIcon) +fun AssetIconProvider.getAssetIconOrFallback(asset: Chain.Asset, fallbackIcon: Icon = AssetIconProvider.fallbackIcon): Icon { + return this.getAssetIconOrFallback(asset.icon, fallbackIcon) } -fun AssetIconProvider.getWhiteAssetIcon(asset: Chain.Asset, fallbackIcon: Icon = this.fallbackIcon): Icon { - return this.getWhiteAssetIcon(asset.icon, fallbackIcon) +fun AssetIconProvider.getAssetIconOrFallback(asset: Chain.Asset, iconMode: AssetIconMode, fallbackIcon: Icon = AssetIconProvider.fallbackIcon): Icon { + return this.getAssetIconOrFallback(asset.icon, iconMode, fallbackIcon) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt index 9ed77ae763..13388f4e1a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/list/AssetsListInteractor.kt @@ -18,13 +18,13 @@ class AssetsListInteractor( private val accountRepository: AccountRepository, private val nftRepository: NftRepository, private val bannerVisibilityRepository: BannerVisibilityRepository, - private val assetsViewModeService: AssetsViewModeRepository + private val assetsViewModeRepository: AssetsViewModeRepository ) { - fun assetsViewModeFlow() = assetsViewModeService.assetsViewModeFlow() + fun assetsViewModeFlow() = assetsViewModeRepository.assetsViewModeFlow() suspend fun setAssetViewMode(assetViewModel: AssetViewMode) { - assetsViewModeService.setAssetsViewMode(assetViewModel) + assetsViewModeRepository.setAssetsViewMode(assetViewModel) } suspend fun fullSyncNft(nft: Nft) = nftRepository.fullNftSync(nft) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt index e651a0c7c3..4f9c0eccce 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt @@ -4,7 +4,7 @@ import io.novafoundation.nova.common.list.GroupedList import io.novafoundation.nova.common.list.toListWithHeaders import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi -import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance @@ -36,7 +36,7 @@ private fun mapAssetsToAssetModels( return assets.map { NetworkAssetUi( mapAssetToAssetModel(it.asset, balance(it.balanceWithOffchain)), - assetIconProvider.getAssetIcon(it.asset.token.configuration) + assetIconProvider.getAssetIconOrFallback(it.asset.token.configuration) ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index 6e88ff09ca..8668b70184 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -3,11 +3,12 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mapper import io.novafoundation.nova.common.list.GroupedList import io.novafoundation.nova.common.list.toListWithHeaders import io.novafoundation.nova.common.presentation.AssetIconProvider +import io.novafoundation.nova.common.presentation.getAssetIconOrFallback import io.novafoundation.nova.common.utils.formatTokenAmount import io.novafoundation.nova.common.utils.formatting.formatAsChange import io.novafoundation.nova.common.utils.orZero import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi -import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup @@ -42,7 +43,7 @@ fun mapTokenAssetGroupToUi( val balance = groupBalance(assetGroup) return TokenGroupUi( itemId = assetGroup.groupId, - tokenIcon = assetIconProvider.getAssetIcon(assetGroup.token.icon), + tokenIcon = assetIconProvider.getAssetIconOrFallback(assetGroup.token.icon), rate = mapCoinRateChange(assetGroup.token.coinRate, assetGroup.token.currency), recentRateChange = assetGroup.token.coinRate?.recentRateChange.orZero().formatAsChange(), rateChangeColorRes = mapCoinRateChangeColorRes(assetGroup.token.coinRate), @@ -66,7 +67,7 @@ private fun mapAssetsToAssetModels( TokenAssetUi( group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), - assetIconProvider.getAssetIcon(it.asset.token.configuration), + assetIconProvider.getAssetIconOrFallback(it.asset.token.configuration), mapChainToUi(it.chain) ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt index 161607ecd6..d6d1a4cc19 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailViewModel.kt @@ -10,7 +10,7 @@ import io.novafoundation.nova.common.utils.Event import io.novafoundation.nova.common.utils.inBackground import io.novafoundation.nova.common.utils.sumByBigInteger import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase -import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.WalletInteractor import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor @@ -208,7 +208,7 @@ class BalanceDetailViewModel( total = mapAmountToAmountModel(asset.total + totalContributed, asset), transferable = mapAmountToAmountModel(asset.transferable, asset), locked = mapAmountToAmountModel(asset.locked + totalContributed, asset), - assetIcon = assetIconProvider.getAssetIcon(asset.token.configuration) + assetIcon = assetIconProvider.getAssetIconOrFallback(asset.token.configuration) ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt index 9f40c2f599..8d96d75247 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/ReceiveViewModel.kt @@ -18,7 +18,7 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAcco import io.novafoundation.nova.feature_account_api.domain.model.addressIn import io.novafoundation.nova.feature_account_api.presenatation.account.icon.createAddressModel import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions -import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.receive.ReceiveInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload @@ -67,7 +67,7 @@ class ReceiveViewModel( TokenReceiver( addressModel = addressIconGenerator.createAddressModel(chain, address, AddressIconGenerator.SIZE_BIG, it.name), chain = mapChainToUi(chain), - chainAssetIcon = assetIconProvider.getAssetIcon(chainAsset) + chainAssetIcon = assetIconProvider.getAssetIconOrFallback(chainAsset) ) } .inBackground() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/model/MultiChainTokenModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/model/MultiChainTokenModel.kt index 1b3b497f24..e8bb7404fb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/model/MultiChainTokenModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/model/MultiChainTokenModel.kt @@ -1,6 +1,7 @@ package io.novafoundation.nova.feature_assets.presentation.tokens.manage.model import io.novafoundation.nova.common.presentation.AssetIconProvider +import io.novafoundation.nova.common.presentation.getAssetIconOrFallback import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.resources.formatListPreview import io.novafoundation.nova.common.utils.images.Icon @@ -27,7 +28,7 @@ class MultiChainTokenMapper( fun mapHeaderToUi(multiChainToken: MultiChainToken): MultiChainTokenModel.HeaderModel { return MultiChainTokenModel.HeaderModel( - icon = assetIconProvider.getAssetIcon(multiChainToken.icon), + icon = assetIconProvider.getAssetIconOrFallback(multiChainToken.icon), symbol = multiChainToken.symbol, networks = constructNetworksSubtitle(multiChainToken) ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt index 2dfc929632..f23d9a1273 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_assets.presentation.transaction.detail.ex import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.base.BaseViewModel import io.novafoundation.nova.common.presentation.AssetIconProvider +import io.novafoundation.nova.common.presentation.getAssetIconOrFallback import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.flowOf import io.novafoundation.nova.common.utils.inBackground @@ -54,7 +55,7 @@ class ExtrinsicDetailViewModel( .share() val operationIcon = flowOf { - assetIconProvider.getAssetIcon(chainAsset().icon) + assetIconProvider.getAssetIconOrFallback(chainAsset().icon) }.shareInBackground() val content = flowOf { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/SwapDetailViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/SwapDetailViewModel.kt index b8a1aea05c..0ea5fa3d21 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/SwapDetailViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/swap/SwapDetailViewModel.kt @@ -14,7 +14,7 @@ import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi import io.novafoundation.nova.feature_account_api.presenatation.account.icon.createAccountAddressModel import io.novafoundation.nova.feature_account_api.presenatation.account.wallet.WalletUiUseCase import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions -import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.model.ChainAssetWithAmountParcelModel @@ -154,7 +154,7 @@ class SwapDetailViewModel( income: Boolean ): SwapAssetView.Model { return SwapAssetView.Model( - assetIcon = assetIconProvider.getAssetIcon(token.configuration), + assetIcon = assetIconProvider.getAssetIconOrFallback(token.configuration), amount = mapAmountToAmountModel(amount, token, estimatedFiat = true), chainUi = mapChainToUi(chainRegistry.getChain(token.configuration.chainId)), amountTextColorRes = if (income) R.color.text_positive else R.color.text_primary diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt index f710389ff2..da56fc1fc7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt @@ -5,14 +5,16 @@ import android.text.TextUtils import android.text.style.ImageSpan import androidx.annotation.ColorRes import androidx.annotation.DrawableRes +import io.novafoundation.nova.common.data.model.AssetIconMode import io.novafoundation.nova.common.presentation.AssetIconProvider +import io.novafoundation.nova.common.presentation.getAssetIconOrFallback import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.buildSpannable import io.novafoundation.nova.common.utils.capitalize import io.novafoundation.nova.common.utils.images.asIcon import io.novafoundation.nova.common.utils.splitSnakeOrCamelCase import io.novafoundation.nova.feature_account_api.presenatation.account.AddressDisplayUseCase -import io.novafoundation.nova.feature_account_api.presenatation.chain.getWhiteAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.presentation.model.AmountParcelModel import io.novafoundation.nova.feature_assets.presentation.model.ChainAssetWithAmountParcelModel @@ -276,7 +278,7 @@ fun mapOperationToOperationModel( subHeader = subHeader.value, subHeaderEllipsize = subHeader.elipsize, statusAppearance = statusAppearance, - operationIcon = assetIconProvider.getWhiteAssetIcon(operation.chainAsset) + operationIcon = assetIconProvider.getAssetIconOrFallback(operation.chainAsset, AssetIconMode.WHITE) ) } diff --git a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt index c0bae59d97..e0897e4fcf 100644 --- a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt +++ b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt @@ -6,7 +6,7 @@ import io.novafoundation.nova.common.resources.formatListPreview import io.novafoundation.nova.common.utils.capitalize import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.common.utils.images.asIcon -import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_governance_api.domain.referendum.track.category.TrackType import io.novafoundation.nova.feature_governance_api.domain.track.Track import io.novafoundation.nova.feature_governance_impl.R @@ -37,7 +37,7 @@ class RealTrackFormatter( return when (trackCategorizer.typeOf(track.name)) { TrackType.ROOT -> TrackModel( name = resourceManager.getString(R.string.referendum_track_root), - icon = assetIconProvider.getAssetIcon(asset, fallbackIcon = R.drawable.ic_block.asIcon()), + icon = assetIconProvider.getAssetIconOrFallback(asset, fallbackIcon = R.drawable.ic_block.asIcon()), ) TrackType.WHITELISTED_CALLER -> TrackModel( diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/SwapConfirmationViewModel.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/SwapConfirmationViewModel.kt index 4cc2e64d8b..d35b2d7767 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/SwapConfirmationViewModel.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/confirmation/SwapConfirmationViewModel.kt @@ -27,7 +27,7 @@ import io.novafoundation.nova.feature_account_api.presenatation.account.wallet.W import io.novafoundation.nova.feature_account_api.presenatation.account.wallet.WalletUiUseCase import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions import io.novafoundation.nova.feature_account_api.presenatation.actions.showAddressActions -import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_swap_core.domain.model.SwapDirection import io.novafoundation.nova.feature_swap_api.domain.model.SwapFee import io.novafoundation.nova.feature_swap_api.domain.model.SwapQuote @@ -292,7 +292,7 @@ class SwapConfirmationViewModel( ): SwapAssetView.Model { val amount = formatAmount(metaAccount, chainAsset, amountInPlanks) return SwapAssetView.Model( - assetIcon = assetIconProvider.getAssetIcon(chainAsset), + assetIcon = assetIconProvider.getAssetIconOrFallback(chainAsset), amount = amount, chainUi = mapChainToUi(chain), ) diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixinFactory.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixinFactory.kt index d64f15daaf..35f1f0bb5c 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixinFactory.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/main/input/SwapAmountInputMixinFactory.kt @@ -4,7 +4,7 @@ import androidx.annotation.StringRes import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.validation.FieldValidator -import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_account_api.presenatation.chain.iconOrFallback import io.novafoundation.nova.feature_swap_impl.R import io.novafoundation.nova.feature_swap_impl.presentation.main.input.SwapAmountInputMixin.SwapInputAssetModel @@ -80,7 +80,7 @@ private class RealSwapAmountInputMixin( val chain = chainRegistry.getChain(chainAsset.chainId) return SwapInputAssetModel( - assetIcon = SwapInputAssetModel.SwapAssetIcon.Chosen(assetIconProvider.getAssetIcon(chainAsset)), + assetIcon = SwapInputAssetModel.SwapAssetIcon.Chosen(assetIconProvider.getAssetIconOrFallback(chainAsset)), title = chainAsset.symbol.value, subtitleIcon = chain.iconOrFallback(), subtitle = chain.name, diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt index 7f87ac6e0e..09e8bf058b 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt @@ -3,7 +3,7 @@ package io.novafoundation.nova.feature_wallet_api.data.mappers import androidx.annotation.StringRes import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager -import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_wallet_api.R import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.presentation.formatters.formatTokenAmount @@ -24,7 +24,7 @@ fun mapAssetToAssetModel( AssetModel( chainId = asset.token.configuration.chainId, chainAssetId = asset.token.configuration.id, - icon = assetIconProvider.getAssetIcon(token.configuration), + icon = assetIconProvider.getAssetIconOrFallback(token.configuration), tokenName = token.configuration.name, tokenSymbol = token.configuration.symbol.value, assetBalance = formattedAmount diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/ChooseAmountModel.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/ChooseAmountModel.kt index b46b57616e..ba8a3b74f8 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/ChooseAmountModel.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/ChooseAmountModel.kt @@ -5,7 +5,7 @@ import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.ensureSuffix import io.novafoundation.nova.common.utils.images.Icon -import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain @@ -31,5 +31,5 @@ internal fun ChooseAmountModel( internal fun ChooseAmountInputModel(chainAsset: Chain.Asset, assetIconProvider: AssetIconProvider): ChooseAmountInputModel = ChooseAmountInputModel( tokenSymbol = chainAsset.symbol.value, - tokenIcon = assetIconProvider.getAssetIcon(chainAsset), + tokenIcon = assetIconProvider.getAssetIconOrFallback(chainAsset), ) diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt index 93d464b140..f8c0879a0a 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/ChainRegistry.kt @@ -6,6 +6,7 @@ import io.novafoundation.nova.common.utils.LOG_TAG import io.novafoundation.nova.common.utils.diffed import io.novafoundation.nova.common.utils.filterList import io.novafoundation.nova.common.utils.inBackground +import io.novafoundation.nova.common.utils.mapList import io.novafoundation.nova.common.utils.mapNotNullToSet import io.novafoundation.nova.common.utils.removeHexPrefix import io.novafoundation.nova.core.ethereum.Web3Api @@ -65,9 +66,8 @@ class ChainRegistry( private val gson: Gson ) : CoroutineScope by CoroutineScope(Dispatchers.Default) { - val currentChains = chainDao.joinChainInfoFlow().map { chains -> - chains.map { mapChainLocalToChain(it, gson) } - } + val currentChains = chainDao.joinChainInfoFlow() + .mapList { mapChainLocalToChain(it, gson) } .diffed() .map { diff -> diff.removed.forEach { unregisterChain(it) } From 2c92c852ca4acee1d7a555210bc56c61b63bc705 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 1 Nov 2024 10:24:31 +0100 Subject: [PATCH 45/78] Update AssetIconProvider.kt --- .../novafoundation/nova/common/presentation/AssetIconProvider.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt b/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt index 2a1fe45762..a174975a4f 100644 --- a/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt +++ b/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt @@ -21,7 +21,6 @@ class RealAssetIconProvider( private val whiteBaseUrl: String ) : AssetIconProvider { - override fun getAssetIconOrFallback(iconName: String): Icon { return getAssetIconOrFallback(iconName, assetsIconModeRepository.getIconMode()) } From 7a7d61e982aedcca2a33a594eb32a192ecfad403 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 1 Nov 2024 10:27:41 +0100 Subject: [PATCH 46/78] Fixed pr notes --- .../recyclerView/expandable/ExpandableAnimationSettings.kt | 4 +++- .../balance/common/AssetExpandableAssetDecorationSettings.kt | 2 +- .../presentation/balance/common/ExpandableAssetsMixin.kt | 1 + .../presentation/balance/list/BalanceListFragment.kt | 5 +++-- .../presentation/balance/search/AssetSearchFragment.kt | 5 +++-- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationSettings.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationSettings.kt index aca4b7a2c5..2d001e0117 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationSettings.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableAnimationSettings.kt @@ -2,4 +2,6 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable import android.view.animation.Interpolator -class ExpandableAnimationSettings(val duration: Long, val interpolator: Interpolator) +class ExpandableAnimationSettings(val duration: Long, val interpolator: Interpolator) { + companion object; +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetExpandableAssetDecorationSettings.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetExpandableAssetDecorationSettings.kt index 7c33240f8d..89a22476b4 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetExpandableAssetDecorationSettings.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetExpandableAssetDecorationSettings.kt @@ -3,4 +3,4 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common import android.view.animation.AccelerateDecelerateInterpolator import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAnimationSettings -fun createAssetExpandableAnimationSettings() = ExpandableAnimationSettings(400, AccelerateDecelerateInterpolator()) +fun ExpandableAnimationSettings.Companion.createForAssets() = ExpandableAnimationSettings(400, AccelerateDecelerateInterpolator()) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt index a59d857965..3cc991dcfb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -29,6 +29,7 @@ interface ExpandableAssetsMixin { val assetModelsFlow: Flow> fun expandToken(tokenGroupUi: TokenGroupUi) + suspend fun switchViewMode() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index 2fdd80a129..7601973c77 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -10,6 +10,7 @@ import dev.chrisbanes.insetter.applyInsetter import io.novafoundation.nova.common.base.BaseFragment import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.hideKeyboard +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAnimationSettings import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi @@ -20,7 +21,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTo import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTokensItemAnimator import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.applyDefaultTo -import io.novafoundation.nova.feature_assets.presentation.balance.common.createAssetExpandableAnimationSettings +import io.novafoundation.nova.feature_assets.presentation.balance.common.createForAssets import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetsHeaderAdapter import io.novafoundation.nova.feature_assets.presentation.model.AssetModel @@ -70,7 +71,7 @@ class BalanceListFragment : balanceListAssets.setHasFixedSize(true) balanceListAssets.adapter = adapter - val animationSettings = createAssetExpandableAnimationSettings() + val animationSettings = ExpandableAnimationSettings.createForAssets() val animator = ExpandableAnimator(balanceListAssets, animationSettings, assetsAdapter) balanceListAssets.addItemDecoration(AssetTokensDecoration(requireContext(), assetsAdapter, animator)) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt index fa310f6b53..40300d348d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt @@ -13,6 +13,7 @@ import io.novafoundation.nova.common.utils.applyStatusBarInsets import io.novafoundation.nova.common.utils.bindTo import io.novafoundation.nova.common.utils.keyboard.hideSoftKeyboard import io.novafoundation.nova.common.utils.keyboard.showSoftKeyboard +import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAnimationSettings import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator import io.novafoundation.nova.common.utils.setVisible import io.novafoundation.nova.feature_assets.R @@ -23,7 +24,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetTo import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.AssetBaseDecoration import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.applyDefaultTo -import io.novafoundation.nova.feature_assets.presentation.balance.common.createAssetExpandableAnimationSettings +import io.novafoundation.nova.feature_assets.presentation.balance.common.createForAssets import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import kotlinx.android.synthetic.main.fragment_asset_search.searchAssetContainer @@ -62,7 +63,7 @@ class AssetSearchFragment : searchAssetList.setHasFixedSize(true) searchAssetList.adapter = assetsAdapter - val animationSettings = createAssetExpandableAnimationSettings() + val animationSettings = ExpandableAnimationSettings.createForAssets() val animator = ExpandableAnimator(searchAssetList, animationSettings, assetsAdapter) searchAssetList.addItemDecoration(AssetTokensDecoration(requireContext(), assetsAdapter, animator)) From 13442726c87d0c41255affd5deefaf7b91822064 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 1 Nov 2024 11:01:37 +0100 Subject: [PATCH 47/78] Use asset icon provider in search screen --- .../nova/feature_assets/di/AssetsFeatureModule.kt | 3 +++ .../presentation/balance/common/ExpandableAssetsMixin.kt | 9 ++++++--- .../presentation/balance/search/di/AssetSearchModule.kt | 2 -- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt index f9d2d0ab5a..06973db737 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt @@ -7,6 +7,7 @@ import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.di.scope.FeatureScope import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.core_db.dao.OperationDao import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository @@ -188,10 +189,12 @@ class AssetsFeatureModule { @Provides @FeatureScope fun provideExpandableAssetsMixinFactory( + assetIconProvider: AssetIconProvider, currencyInteractor: CurrencyInteractor, assetsViewModeRepository: AssetsViewModeRepository ): ExpandableAssetsMixinFactory { return ExpandableAssetsMixinFactory( + assetIconProvider, currencyInteractor, assetsViewModeRepository ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt index 3cc991dcfb..cc9c28cdf3 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common import io.novafoundation.nova.common.data.model.switch import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository +import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.utils.toggle import io.novafoundation.nova.common.utils.updateValue import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult @@ -15,12 +16,13 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine class ExpandableAssetsMixinFactory( + private val assetIconProvider: AssetIconProvider, private val currencyInteractor: CurrencyInteractor, private val assetsViewModeRepository: AssetsViewModeRepository ) { fun create(assetsFlow: Flow): ExpandableAssetsMixin { - return RealExpandableAssetsMixin(assetsFlow, currencyInteractor, assetsViewModeRepository) + return RealExpandableAssetsMixin(assetsFlow, currencyInteractor, assetIconProvider, assetsViewModeRepository) } } @@ -36,6 +38,7 @@ interface ExpandableAssetsMixin { class RealExpandableAssetsMixin( assetsFlow: Flow, currencyInteractor: CurrencyInteractor, + private val assetIconProvider: AssetIconProvider, private val assetsViewModeRepository: AssetsViewModeRepository, ) : ExpandableAssetsMixin { @@ -49,8 +52,8 @@ class RealExpandableAssetsMixin( selectedCurrency ) { assetesByViewMode, expandedTokens, currency -> when (assetesByViewMode) { - is AssetsByViewModeResult.ByNetworks -> assetesByViewMode.assets.mapGroupedAssetsToUi(currency) - is AssetsByViewModeResult.ByTokens -> assetesByViewMode.tokens.mapGroupedAssetsToUi( + is AssetsByViewModeResult.ByNetworks -> assetesByViewMode.assets.mapGroupedAssetsToUi(assetIconProvider, currency) + is AssetsByViewModeResult.ByTokens -> assetesByViewMode.tokens.mapGroupedAssetsToUi(assetIconProvider, assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt index efc80c48e2..4cfd7ddb97 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt @@ -30,14 +30,12 @@ class AssetSearchModule { fun provideViewModel( router: AssetsRouter, interactorFactory: AssetSearchInteractorFactory, - currencyInteractor: CurrencyInteractor, externalBalancesInteractor: ExternalBalancesInteractor, expandableAssetsMixinFactory: ExpandableAssetsMixinFactory ): ViewModel { return AssetSearchViewModel( router = router, interactorFactory = interactorFactory, - currencyInteractor = currencyInteractor, externalBalancesInteractor = externalBalancesInteractor, expandableAssetsMixinFactory = expandableAssetsMixinFactory ) From 64197b720b92e8f152fe3a6f494a27f2d3d9bf33 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 1 Nov 2024 11:50:40 +0100 Subject: [PATCH 48/78] Update BalanceListModule.kt --- .../presentation/balance/list/di/BalanceListModule.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt index c154b82db9..ad0985e49b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt @@ -59,14 +59,12 @@ class BalanceListModule { @Provides @ScreenScope fun provideAssetListMixinFactory( - assetIconProvider: AssetIconProvider, walletInteractor: WalletInteractor, assetsListInteractor: AssetsListInteractor, externalBalancesInteractor: ExternalBalancesInteractor, expandableAssetsMixinFactory: ExpandableAssetsMixinFactory ): AssetListMixinFactory { return AssetListMixinFactory( - assetIconProvider, walletInteractor, assetsListInteractor, externalBalancesInteractor, From 7eb880251d6c9c9b91c3460c1032bc3b2fdf4c55 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 1 Nov 2024 09:54:38 +0100 Subject: [PATCH 49/78] - Fixed items dissapearing - Fixed clipping bounds - Fixed crash during animation --- .../expandable/ExpandableItemAnimator.kt | 15 ++++++++--- .../expandable/ExpandableItemDecoration.kt | 2 ++ .../balance/common/AssetListMixin.kt | 26 +++++++++++++++++-- .../balance/common/AssetTokensDecoration.kt | 4 +-- .../balance/common/AssetTokensItemAnimator.kt | 17 +++++++----- 5 files changed, 49 insertions(+), 15 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt index daab2f4150..2c7a806f42 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemAnimator.kt @@ -121,7 +121,6 @@ abstract class ExpandableItemAnimator( // Reset remove state helps clear alpha and scale when animation is being to be canceled if (pendingRemoveAnimations.contains(holder)) { holder.itemView.animate().cancel() - resetRemoveState(holder) } if (pendingMoveAnimations.contains(holder)) { @@ -219,6 +218,7 @@ abstract class ExpandableItemAnimator( .setDuration(settings.duration) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { + resetRemoveState(holder) removeFinished(holder) animation.setListener(null) } @@ -242,13 +242,13 @@ abstract class ExpandableItemAnimator( } override fun endAnimations() { - pendingAddAnimations.forEach { it.itemView.animate().cancel() } + pendingAddAnimations.iterator().forEach { it.itemView.animate().cancel() } pendingAddAnimations.clear() - pendingRemoveAnimations.forEach { it.itemView.animate().cancel() } + pendingRemoveAnimations.iterator().forEach { it.itemView.animate().cancel() } pendingRemoveAnimations.clear() - pendingMoveAnimations.forEach { it.itemView.animate().cancel() } + pendingMoveAnimations.iterator().forEach { it.itemView.animate().cancel() } pendingMoveAnimations.clear() addAnimations.clear() @@ -288,5 +288,12 @@ abstract class ExpandableItemAnimator( if (holder in pendingMoveAnimations) return dispatchAnimationFinished(holder) + dispatchFinishedWhenDone() + } + + private fun dispatchFinishedWhenDone() { + if (!isRunning) { + dispatchAnimationsFinished() + } } } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt index ec30ca0b92..42c275fcf2 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable import android.graphics.Canvas import android.graphics.Rect +import android.util.Log import android.view.View import androidx.core.view.children import androidx.recyclerview.widget.ConcatAdapter @@ -14,6 +15,7 @@ import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.Expa import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem +import kotlin.system.measureTimeMillis private data class ItemWithViewHolder(val position: Int, val item: ExpandableBaseItem, val viewHolder: ViewHolder?) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index aca876dbb8..30b644430a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common +import android.util.Log import io.novafoundation.nova.common.data.model.AssetViewMode import io.novafoundation.nova.common.utils.shareInBackground import io.novafoundation.nova.feature_assets.domain.WalletInteractor @@ -7,6 +8,10 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.assets.list.AssetsListInteractor import io.novafoundation.nova.feature_assets.domain.assets.models.byNetworks import io.novafoundation.nova.feature_assets.domain.assets.models.byTokens +import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork +import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance +import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup +import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_wallet_api.domain.model.Asset @@ -16,6 +21,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlin.system.measureTimeMillis class AssetListMixinFactory( private val walletInteractor: WalletInteractor, @@ -74,8 +80,24 @@ class RealAssetListMixin( assetsViewModeFlow ) { assets, externalBalances, viewMode -> when (viewMode) { - AssetViewMode.NETWORKS -> walletInteractor.groupAssetsByNetwork(assets, externalBalances).byNetworks() - AssetViewMode.TOKENS -> walletInteractor.groupAssetsByToken(assets, externalBalances).byTokens() + AssetViewMode.NETWORKS -> { + var networks: Map> + val time = measureTimeMillis { + networks = walletInteractor.groupAssetsByNetwork(assets, externalBalances) + } + Log.d("AssetListMixin", "tokens: $time") + networks.byNetworks() + } + + AssetViewMode.TOKENS -> { + var networks: Map> + val time = measureTimeMillis { + networks = walletInteractor.groupAssetsByToken(assets, externalBalances) + } + Log.d("AssetListMixin", "tokens: $time") + networks.byTokens() + + } } }.distinctUntilChanged() .shareInBackground() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt index 595937b295..d2bfa19818 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt @@ -94,10 +94,10 @@ class AssetTokensDecoration( children.forEach { val childrenBottomClipInset = (it.itemView.bottom + it.itemView.translationY.roundToInt()) - childrenBlock.bottom val childrenTopClipInset = childrenBlock.top - (it.itemView.top + it.itemView.translationY.roundToInt()) - if (childrenBottomClipInset > 0) { + if (childrenTopClipInset > 0 || childrenBottomClipInset > 0) { it.itemView.clipBounds = Rect( 0, - childrenTopClipInset.coerceAtLeast(0), + childrenTopClipInset, it.itemView.width, it.itemView.height - childrenBottomClipInset ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt index e4f1894c2e..00176627b2 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensItemAnimator.kt @@ -6,6 +6,8 @@ import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableAni import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableItemAnimator import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.ExpandableAnimator +private const val REMOVE_SCALE = 0.9f + class AssetTokensItemAnimator( settings: ExpandableAnimationSettings, expandableAnimator: ExpandableAnimator @@ -15,7 +17,9 @@ class AssetTokensItemAnimator( ) { override fun preAddImpl(holder: RecyclerView.ViewHolder) { - resetRemoveState(holder) + holder.itemView.alpha = 0f + holder.itemView.scaleX = REMOVE_SCALE + holder.itemView.scaleY = REMOVE_SCALE } override fun getAddAnimator(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { @@ -32,8 +36,8 @@ class AssetTokensItemAnimator( override fun getRemoveAnimator(holder: RecyclerView.ViewHolder): ViewPropertyAnimator { return holder.itemView.animate() .alpha(0f) - .scaleX(0.90f) - .scaleY(0.90f) + .scaleX(REMOVE_SCALE) + .scaleY(REMOVE_SCALE) } override fun preMoveImpl(holder: RecyclerView.ViewHolder, fromY: Int, toY: Int) { @@ -50,7 +54,6 @@ class AssetTokensItemAnimator( super.endAnimation(viewHolder) viewHolder.itemView.translationY = 0f - viewHolder.itemView.alpha = 0f viewHolder.itemView.alpha = 1f viewHolder.itemView.scaleX = 1f viewHolder.itemView.scaleY = 1f @@ -63,9 +66,9 @@ class AssetTokensItemAnimator( } override fun resetRemoveState(holder: RecyclerView.ViewHolder) { - holder.itemView.alpha = 0f - holder.itemView.scaleX = 0.90f - holder.itemView.scaleY = 0.90f + holder.itemView.alpha = 1f + holder.itemView.scaleX = 1f + holder.itemView.scaleY = 1f } override fun resetMoveState(holder: RecyclerView.ViewHolder) { From 55910b7f08b46bb445e1328f7978d30fb7aa285a Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 1 Nov 2024 14:01:38 +0100 Subject: [PATCH 50/78] Clean code --- .../expandable/ExpandableItemDecoration.kt | 2 -- .../balance/common/AssetListMixin.kt | 26 ++----------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt index 42c275fcf2..ec30ca0b92 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/recyclerView/expandable/ExpandableItemDecoration.kt @@ -2,7 +2,6 @@ package io.novafoundation.nova.common.utils.recyclerView.expandable import android.graphics.Canvas import android.graphics.Rect -import android.util.Log import android.view.View import androidx.core.view.children import androidx.recyclerview.widget.ConcatAdapter @@ -15,7 +14,6 @@ import io.novafoundation.nova.common.utils.recyclerView.expandable.animator.Expa import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableBaseItem import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem -import kotlin.system.measureTimeMillis private data class ItemWithViewHolder(val position: Int, val item: ExpandableBaseItem, val viewHolder: ViewHolder?) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index 30b644430a..aca876dbb8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -1,6 +1,5 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common -import android.util.Log import io.novafoundation.nova.common.data.model.AssetViewMode import io.novafoundation.nova.common.utils.shareInBackground import io.novafoundation.nova.feature_assets.domain.WalletInteractor @@ -8,10 +7,6 @@ import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInter import io.novafoundation.nova.feature_assets.domain.assets.list.AssetsListInteractor import io.novafoundation.nova.feature_assets.domain.assets.models.byNetworks import io.novafoundation.nova.feature_assets.domain.assets.models.byTokens -import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork -import io.novafoundation.nova.feature_assets.domain.common.AssetWithOffChainBalance -import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup -import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_wallet_api.domain.model.Asset @@ -21,7 +16,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged -import kotlin.system.measureTimeMillis class AssetListMixinFactory( private val walletInteractor: WalletInteractor, @@ -80,24 +74,8 @@ class RealAssetListMixin( assetsViewModeFlow ) { assets, externalBalances, viewMode -> when (viewMode) { - AssetViewMode.NETWORKS -> { - var networks: Map> - val time = measureTimeMillis { - networks = walletInteractor.groupAssetsByNetwork(assets, externalBalances) - } - Log.d("AssetListMixin", "tokens: $time") - networks.byNetworks() - } - - AssetViewMode.TOKENS -> { - var networks: Map> - val time = measureTimeMillis { - networks = walletInteractor.groupAssetsByToken(assets, externalBalances) - } - Log.d("AssetListMixin", "tokens: $time") - networks.byTokens() - - } + AssetViewMode.NETWORKS -> walletInteractor.groupAssetsByNetwork(assets, externalBalances).byNetworks() + AssetViewMode.TOKENS -> walletInteractor.groupAssetsByToken(assets, externalBalances).byTokens() } }.distinctUntilChanged() .shareInBackground() From 6da4a7d2e55a11a6f6d6fd1ea4f7dff0c57bcbd0 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Mon, 4 Nov 2024 10:54:29 +0100 Subject: [PATCH 51/78] - Remove background for IconButton - Supported spans for floated values in asset list --- .../nova/common/presentation/ColoredText.kt | 2 +- .../nova/common/utils/SpannableDSL.kt | 6 ++-- .../utils/formatting/NumberFormatters.kt | 2 +- .../nova/common/view/IconButton.kt | 3 +- .../nova/common/view/TableCellView.kt | 4 +-- .../feature_assets/di/AssetsFeatureModule.kt | 2 ++ .../balance/common/ExpandableAssetsMixin.kt | 8 +++-- .../common/mappers/AssetMappersCommon.kt | 5 ++- .../common/mappers/NetworkAssetMappers.kt | 7 +++-- .../common/mappers/TokenAssetMappers.kt | 19 ++++++++---- .../balance/list/BalanceListViewModel.kt | 30 ++---------------- .../list/model/items/NetworkGroupUi.kt | 2 +- .../flow/asset/AssetFlowViewModel.kt | 4 +-- .../send/flow/asset/AssetSendFlowViewModel.kt | 4 +-- .../swap/asset/AssetSwapFlowViewModel.kt | 4 +-- feature-assets/src/main/res/values/dimens.xml | 1 + .../setup/common/model/AmountChangeModel.kt | 12 +++---- .../setup/common/view/AmountChangesView.kt | 6 ++-- .../unlock/list/model/GovernanceLockModel.kt | 2 +- .../presentation/view/GovernanceLocksView.kt | 2 +- .../presentation/view/NovaChipView.kt | 4 +-- .../nft/common/model/NftPriceModel.kt | 4 +-- .../main/components/alerts/AlertModel.kt | 4 +-- .../components/networkInfo/NetworkInfoItem.kt | 2 +- .../presentation/model/AmountFormatters.kt | 31 +++++++++++++++++++ .../presentation/model/AmountModel.kt | 13 ++++++-- .../presentation/view/PriceSectionView.kt | 2 +- .../presentation/view/TotalAmountView.kt | 2 +- 28 files changed, 112 insertions(+), 75 deletions(-) create mode 100644 feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt diff --git a/common/src/main/java/io/novafoundation/nova/common/presentation/ColoredText.kt b/common/src/main/java/io/novafoundation/nova/common/presentation/ColoredText.kt index 2fe200f4a3..89dc088417 100644 --- a/common/src/main/java/io/novafoundation/nova/common/presentation/ColoredText.kt +++ b/common/src/main/java/io/novafoundation/nova/common/presentation/ColoredText.kt @@ -6,7 +6,7 @@ import io.novafoundation.nova.common.utils.letOrHide import io.novafoundation.nova.common.utils.setTextColorRes data class ColoredText( - val text: String, + val text: CharSequence, @ColorRes val colorRes: Int, ) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/SpannableDSL.kt b/common/src/main/java/io/novafoundation/nova/common/utils/SpannableDSL.kt index e358d3a78c..2636f883f5 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/SpannableDSL.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/SpannableDSL.kt @@ -48,7 +48,7 @@ class SpannableBuilder(private val resourceManager: ResourceManager) { private val builder = SpannableStringBuilder() - fun appendColored(text: String, @ColorRes color: Int) { + fun appendColored(text: CharSequence, @ColorRes color: Int) { val span = ForegroundColorSpan(resourceManager.getColor(color)) append(text, span) @@ -60,7 +60,7 @@ class SpannableBuilder(private val resourceManager: ResourceManager) { return appendColored(text, color) } - fun append(text: String) { + fun append(text: CharSequence) { builder.append(text) } @@ -75,7 +75,7 @@ class SpannableBuilder(private val resourceManager: ResourceManager) { fun build(): SpannableString = SpannableString(builder) - private fun append(text: String, span: Any): SpannableBuilder { + private fun append(text: CharSequence, span: Any): SpannableBuilder { builder.append(text, span, Spanned.SPAN_INCLUSIVE_INCLUSIVE) return this diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/formatting/NumberFormatters.kt b/common/src/main/java/io/novafoundation/nova/common/utils/formatting/NumberFormatters.kt index 8c8b907eef..47970dedea 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/formatting/NumberFormatters.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/formatting/NumberFormatters.kt @@ -183,7 +183,7 @@ fun decimalFormatterFor(pattern: String, roundingMode: RoundingMode): DecimalFor } } -fun String.toAmountWithFraction(): AmountWithFraction { +fun CharSequence.toAmountWithFraction(): AmountWithFraction { val amountAndFraction = this.split(DECIMAL_SEPARATOR) val amount = amountAndFraction[0] val fraction = amountAndFraction.getOrNull(1) diff --git a/common/src/main/java/io/novafoundation/nova/common/view/IconButton.kt b/common/src/main/java/io/novafoundation/nova/common/view/IconButton.kt index aae822e54f..3a73e6bf75 100644 --- a/common/src/main/java/io/novafoundation/nova/common/view/IconButton.kt +++ b/common/src/main/java/io/novafoundation/nova/common/view/IconButton.kt @@ -8,6 +8,7 @@ import io.novafoundation.nova.common.R import io.novafoundation.nova.common.utils.WithContextExtensions import io.novafoundation.nova.common.utils.updatePadding import io.novafoundation.nova.common.utils.useAttributes +import io.novafoundation.nova.common.view.shape.getMaskedRipple class IconButton @JvmOverloads constructor( context: Context, @@ -18,7 +19,7 @@ class IconButton @JvmOverloads constructor( init { updatePadding(top = 6.dp, bottom = 6.dp, start = 12.dp, end = 12.dp) - background = addRipple(getRoundedCornerDrawable(R.color.button_background_secondary)) + background = context.getMaskedRipple(cornerSizeInDp = 10) attrs?.let(::applyAttributes) } diff --git a/common/src/main/java/io/novafoundation/nova/common/view/TableCellView.kt b/common/src/main/java/io/novafoundation/nova/common/view/TableCellView.kt index 4da2908487..b87c1a8ff6 100644 --- a/common/src/main/java/io/novafoundation/nova/common/view/TableCellView.kt +++ b/common/src/main/java/io/novafoundation/nova/common/view/TableCellView.kt @@ -195,7 +195,7 @@ open class TableCellView @JvmOverloads constructor( tableCellTitle.setDrawableStart(icon, widthInDp = 16, paddingInDp = 4, tint = tintRes) } - fun showValue(primary: CharSequence, secondary: String? = null) { + fun showValue(primary: CharSequence, secondary: CharSequence? = null) { postToSelf { contentGroup.makeVisible() @@ -278,7 +278,7 @@ open class TableCellView @JvmOverloads constructor( } } -fun TableCellView.showValueOrHide(primary: CharSequence?, secondary: String? = null) { +fun TableCellView.showValueOrHide(primary: CharSequence?, secondary: CharSequence? = null) { if (primary != null) { showValue(primary, secondary) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt index f9d2d0ab5a..fc30287414 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt @@ -188,10 +188,12 @@ class AssetsFeatureModule { @Provides @FeatureScope fun provideExpandableAssetsMixinFactory( + resourceManager: ResourceManager, currencyInteractor: CurrencyInteractor, assetsViewModeRepository: AssetsViewModeRepository ): ExpandableAssetsMixinFactory { return ExpandableAssetsMixinFactory( + resourceManager, currencyInteractor, assetsViewModeRepository ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt index a59d857965..e75cbe57d9 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common import io.novafoundation.nova.common.data.model.switch import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository +import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.toggle import io.novafoundation.nova.common.utils.updateValue import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult @@ -15,12 +16,13 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine class ExpandableAssetsMixinFactory( + private val resourceManager: ResourceManager, private val currencyInteractor: CurrencyInteractor, private val assetsViewModeRepository: AssetsViewModeRepository ) { fun create(assetsFlow: Flow): ExpandableAssetsMixin { - return RealExpandableAssetsMixin(assetsFlow, currencyInteractor, assetsViewModeRepository) + return RealExpandableAssetsMixin(resourceManager, assetsFlow, currencyInteractor, assetsViewModeRepository) } } @@ -33,6 +35,7 @@ interface ExpandableAssetsMixin { } class RealExpandableAssetsMixin( + private val resourceManager: ResourceManager, assetsFlow: Flow, currencyInteractor: CurrencyInteractor, private val assetsViewModeRepository: AssetsViewModeRepository, @@ -48,8 +51,9 @@ class RealExpandableAssetsMixin( selectedCurrency ) { assetesByViewMode, expandedTokens, currency -> when (assetesByViewMode) { - is AssetsByViewModeResult.ByNetworks -> assetesByViewMode.assets.mapGroupedAssetsToUi(currency) + is AssetsByViewModeResult.ByNetworks -> assetesByViewMode.assets.mapGroupedAssetsToUi(resourceManager, currency) is AssetsByViewModeResult.ByTokens -> assetesByViewMode.tokens.mapGroupedAssetsToUi( + resourceManager = resourceManager, assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt index a0230ef97c..28abb0848b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt @@ -1,6 +1,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mappers import androidx.annotation.ColorRes +import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.formatting.formatAsChange import io.novafoundation.nova.common.utils.isNonNegative import io.novafoundation.nova.common.utils.isZero @@ -14,6 +15,7 @@ import io.novafoundation.nova.feature_currency_api.presentation.formatters.forma import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.CoinRateChange import io.novafoundation.nova.feature_wallet_api.domain.model.Token +import io.novafoundation.nova.feature_wallet_api.presentation.model.formatBalanceWithFraction import io.novafoundation.nova.feature_wallet_api.presentation.model.mapAmountToAmountModel import java.math.BigDecimal @@ -23,6 +25,7 @@ fun mapCoinRateChange(coinRateChange: CoinRateChange?, currency: Currency): Stri } fun mapAssetToAssetModel( + resourceManager: ResourceManager, asset: Asset, balance: PricedAmount ): AssetModel { @@ -32,7 +35,7 @@ fun mapAssetToAssetModel( amount = balance.amount, asset = asset, includeAssetTicker = false - ) + ).formatBalanceWithFraction(resourceManager, R.dimen.asset_balance_fraction_size) ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt index 85be66a4cb..09cf54fa5a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mapper import io.novafoundation.nova.common.list.GroupedList import io.novafoundation.nova.common.list.toListWithHeaders +import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.common.NetworkAssetGroup @@ -15,21 +16,23 @@ import io.novafoundation.nova.feature_currency_api.presentation.formatters.forma import java.math.BigDecimal fun GroupedList.mapGroupedAssetsToUi( + resourceManager: ResourceManager, currency: Currency, groupBalance: (NetworkAssetGroup) -> BigDecimal = NetworkAssetGroup::groupTotalBalanceFiat, balance: (AssetBalance) -> PricedAmount = AssetBalance::total, ): List { return mapKeys { (assetGroup, _) -> mapAssetGroupToUi(assetGroup, currency, groupBalance) } - .mapValues { (group, assets) -> mapAssetsToAssetModels(assets, balance) } + .mapValues { (_, assets) -> mapAssetsToAssetModels(resourceManager, assets, balance) } .toListWithHeaders() .filterIsInstance() } private fun mapAssetsToAssetModels( + resourceManager: ResourceManager, assets: List, balance: (AssetBalance) -> PricedAmount ): List { - return assets.map { NetworkAssetUi(mapAssetToAssetModel(it.asset, balance(it.balanceWithOffchain))) } + return assets.map { NetworkAssetUi(mapAssetToAssetModel(resourceManager, it.asset, balance(it.balanceWithOffchain))) } } fun mapAssetGroupToUi( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index b621eefd4c..d85248b949 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -2,10 +2,12 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mapper import io.novafoundation.nova.common.list.GroupedList import io.novafoundation.nova.common.list.toListWithHeaders +import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.formatTokenAmount import io.novafoundation.nova.common.utils.formatting.formatAsChange import io.novafoundation.nova.common.utils.orZero import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi +import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.domain.common.PricedAmount import io.novafoundation.nova.feature_assets.domain.common.AssetWithNetwork import io.novafoundation.nova.feature_assets.domain.common.TokenAssetGroup @@ -15,15 +17,17 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.ite import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel +import io.novafoundation.nova.feature_wallet_api.presentation.model.formatBalanceWithFraction fun GroupedList.mapGroupedAssetsToUi( + resourceManager: ResourceManager, assetFilter: (groupId: String, List) -> List = { _, assets -> assets }, groupBalance: (TokenAssetGroup) -> PricedAmount = { it.groupBalance.total }, balance: (AssetBalance) -> PricedAmount = AssetBalance::total, ): List { - return mapKeys { (group, assets) -> mapTokenAssetGroupToUi(group, assets, groupBalance) } + return mapKeys { (group, assets) -> mapTokenAssetGroupToUi(resourceManager, group, assets, groupBalance) } .mapValues { (group, assets) -> - val assetModels = mapAssetsToAssetModels(group, assets, balance) + val assetModels = mapAssetsToAssetModels(resourceManager, group, assets, balance) assetFilter(group.itemId, assetModels) } .toListWithHeaders() @@ -31,6 +35,7 @@ fun GroupedList.mapGroupedAssetsToUi( } fun mapTokenAssetGroupToUi( + resourceManager: ResourceManager, assetGroup: TokenAssetGroup, assets: List, groupBalance: (TokenAssetGroup) -> PricedAmount = { it.groupBalance.total } @@ -47,27 +52,29 @@ fun mapTokenAssetGroupToUi( balance = AmountModel( token = balance.amount.formatTokenAmount(), fiat = balance.fiat.formatAsCurrency(assetGroup.token.currency) - ), - groupType = mapType(assetGroup, assets, groupBalance) + ).formatBalanceWithFraction(resourceManager, R.dimen.asset_balance_fraction_size), + groupType = mapType(resourceManager, assetGroup, assets, groupBalance) ) } private fun mapAssetsToAssetModels( + resourceManager: ResourceManager, group: TokenGroupUi, assets: List, balance: (AssetBalance) -> PricedAmount ): List { - return assets.map { TokenAssetUi(group.getId(), mapAssetToAssetModel(it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } + return assets.map { TokenAssetUi(group.getId(), mapAssetToAssetModel(resourceManager, it.asset, balance(it.balanceWithOffChain)), mapChainToUi(it.chain)) } } private fun mapType( + resourceManager: ResourceManager, assetGroup: TokenAssetGroup, assets: List, groupBalance: (TokenAssetGroup) -> PricedAmount ): TokenGroupUi.GroupType { return if (assets.size == 1) { val balance = groupBalance(assetGroup) - TokenGroupUi.GroupType.SingleItem(mapAssetToAssetModel(assets.first().asset, balance)) + TokenGroupUi.GroupType.SingleItem(mapAssetToAssetModel(resourceManager, assets.first().asset, balance)) } else { TokenGroupUi.GroupType.Group } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt index cbdc7f0cc5..95f4991440 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt @@ -1,9 +1,5 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list -import android.text.Spannable -import android.text.SpannableStringBuilder -import android.text.style.AbsoluteSizeSpan -import android.text.style.ForegroundColorSpan import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope @@ -14,7 +10,6 @@ import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.Event import io.novafoundation.nova.common.utils.formatting.format import io.novafoundation.nova.common.utils.formatting.formatAsPercentage -import io.novafoundation.nova.common.utils.formatting.toAmountWithFraction import io.novafoundation.nova.common.utils.inBackground import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_account_api.domain.model.MetaAccount @@ -29,6 +24,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.mode import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.model.BalanceBreakdownTotal import io.novafoundation.nova.feature_assets.presentation.balance.breakdown.model.TotalBalanceBreakdownModel import io.novafoundation.nova.feature_assets.presentation.balance.common.AssetListMixinFactory +import io.novafoundation.nova.feature_wallet_api.presentation.model.formatBalanceWithFraction import io.novafoundation.nova.feature_assets.presentation.balance.list.model.NftPreviewUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.TotalBalanceModel import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetViewModeModel @@ -89,6 +85,7 @@ class BalanceListViewModel( { walletInteractor.syncAssetsRates(selectedCurrency.first()) }, walletInteractor::syncAllNfts ) + val assetListMixin = assetListMixinFactory.create(viewModelScope) private val externalBalancesFlow = assetListMixin.externalBalancesFlow @@ -129,7 +126,7 @@ class BalanceListViewModel( val currency = selectedCurrency.first() TotalBalanceModel( isBreakdownAbailable = breakdown.breakdown.isNotEmpty(), - totalBalanceFiat = breakdown.total.simpleFormatAsCurrency(currency).formatAsTotalBalance(), + totalBalanceFiat = breakdown.total.simpleFormatAsCurrency(currency).formatBalanceWithFraction(resourceManager, R.dimen.total_balance_fraction_size), lockedBalanceFiat = breakdown.locksTotal.amount.formatAsCurrency(currency), enableSwap = swapSupported ) @@ -293,27 +290,6 @@ class BalanceListViewModel( } } - private fun String.formatAsTotalBalance(): CharSequence { - val amountWithFraction = toAmountWithFraction() - - val textColor = resourceManager.getColor(R.color.text_secondary) - val colorSpan = ForegroundColorSpan(textColor) - val sizeSpan = AbsoluteSizeSpan(resourceManager.getDimensionPixelSize(R.dimen.total_balance_fraction_size)) - - return with(amountWithFraction) { - val spannableBuilder = SpannableStringBuilder() - .append(amount) - if (fraction != null) { - spannableBuilder.append(separator + fraction) - val startIndex = amount.length - val endIndex = amount.length + separator.length + fraction!!.length - spannableBuilder.setSpan(colorSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) - spannableBuilder.setSpan(sizeSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) - } - spannableBuilder - } - } - fun sendClicked() { router.openSendFlow() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkGroupUi.kt index 6576e6246c..d7e4909f4e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkGroupUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/NetworkGroupUi.kt @@ -4,7 +4,7 @@ import io.novafoundation.nova.feature_account_api.presenatation.chain.ChainUi data class NetworkGroupUi( val chainUi: ChainUi, - val groupBalanceFiat: String + val groupBalanceFiat: CharSequence ) : AssetGroupRvItem { override val itemId: String = chainUi.id diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index a703a589e8..617fa103b8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -85,11 +85,11 @@ abstract class AssetFlowViewModel( } open fun mapNetworkAssets(assets: Map>, currency: Currency): List { - return assets.mapGroupedAssetsToUi(currency) + return assets.mapGroupedAssetsToUi(resourceManager, currency) } open fun mapTokensAssets(assets: Map>): List { - return assets.map { mapTokenAssetGroupToUi(it.key, assets = it.value) } + return assets.map { mapTokenAssetGroupToUi(resourceManager, it.key, assets = it.value) } } internal fun validate(assetModel: AssetModel, onAccept: (AssetModel) -> Unit) { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt index da7b1aa180..019b45fa4b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt @@ -64,12 +64,12 @@ class AssetSendFlowViewModel( } override fun mapNetworkAssets(assets: Map>, currency: Currency): List { - return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, AssetBalance::transferable) + return assets.mapGroupedAssetsToUi(resourceManager, currency, NetworkAssetGroup::groupTransferableBalanceFiat, AssetBalance::transferable) } override fun mapTokensAssets(assets: Map>): List { return assets.map { (group, assets) -> - mapTokenAssetGroupToUi(group, assets = assets) { it.groupBalance.transferable } + mapTokenAssetGroupToUi(resourceManager, group, assets = assets) { it.groupBalance.transferable } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index 3adaa7e0e2..1259f7eeff 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -92,12 +92,12 @@ class AssetSwapFlowViewModel( } override fun mapNetworkAssets(assets: Map>, currency: Currency): List { - return assets.mapGroupedAssetsToUi(currency, NetworkAssetGroup::groupTransferableBalanceFiat, AssetBalance::transferable) + return assets.mapGroupedAssetsToUi(resourceManager, currency, NetworkAssetGroup::groupTransferableBalanceFiat, AssetBalance::transferable) } override fun mapTokensAssets(assets: Map>): List { return assets.map { (group, assets) -> - mapTokenAssetGroupToUi(group, assets = assets) { it.groupBalance.transferable } + mapTokenAssetGroupToUi(resourceManager, group, assets = assets) { it.groupBalance.transferable } } } } diff --git a/feature-assets/src/main/res/values/dimens.xml b/feature-assets/src/main/res/values/dimens.xml index 29078c48e4..a30e9e8e00 100644 --- a/feature-assets/src/main/res/values/dimens.xml +++ b/feature-assets/src/main/res/values/dimens.xml @@ -3,4 +3,5 @@ 64dp 80dp 24sp + 15sp \ No newline at end of file diff --git a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/referenda/vote/setup/common/model/AmountChangeModel.kt b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/referenda/vote/setup/common/model/AmountChangeModel.kt index 0745cea501..fc27f44c15 100644 --- a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/referenda/vote/setup/common/model/AmountChangeModel.kt +++ b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/referenda/vote/setup/common/model/AmountChangeModel.kt @@ -6,22 +6,22 @@ import io.novafoundation.nova.feature_governance_impl.R import io.novafoundation.nova.feature_governance_impl.presentation.referenda.vote.setup.common.model.AmountChangeModel.DifferenceModel class AmountChangeModel( - val to: String, - val from: String?, + val to: CharSequence, + val from: CharSequence?, val difference: DifferenceModel? ) { class DifferenceModel( @DrawableRes val icon: Int, - val text: String, + val text: CharSequence, @ColorRes val color: Int ) } fun AmountChangeModel( - from: String?, - to: String, - difference: String?, + from: CharSequence?, + to: CharSequence, + difference: CharSequence?, positive: Boolean? ): AmountChangeModel { val differenceModel = if (positive != null && difference != null) { diff --git a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/referenda/vote/setup/common/view/AmountChangesView.kt b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/referenda/vote/setup/common/view/AmountChangesView.kt index 6a99b7ec16..5dccda2de6 100644 --- a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/referenda/vote/setup/common/view/AmountChangesView.kt +++ b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/referenda/vote/setup/common/view/AmountChangesView.kt @@ -39,7 +39,7 @@ class AmountChangesView @JvmOverloads constructor( attrs?.let { applyAttributes(it) } } - fun setFrom(value: String?) { + fun setFrom(value: CharSequence?) { if (value != null) { valueChangesFrom.text = value valueChangesFromGroup.makeVisible() @@ -48,11 +48,11 @@ class AmountChangesView @JvmOverloads constructor( } } - fun setTo(value: String) { + fun setTo(value: CharSequence) { valueChangesTo.text = value } - fun setDifference(@DrawableRes icon: Int, text: String, @ColorRes textColor: Int) { + fun setDifference(@DrawableRes icon: Int, text: CharSequence, @ColorRes textColor: Int) { valueChangesDifference.makeVisible() valueChangesDifference.setDrawableStart(icon, widthInDp = 16, tint = textColor) diff --git a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/unlock/list/model/GovernanceLockModel.kt b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/unlock/list/model/GovernanceLockModel.kt index d0da0474e7..9425f55b96 100644 --- a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/unlock/list/model/GovernanceLockModel.kt +++ b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/unlock/list/model/GovernanceLockModel.kt @@ -6,7 +6,7 @@ import io.novafoundation.nova.common.utils.formatting.TimerValue data class GovernanceLockModel( val index: Int, - val amount: String, + val amount: CharSequence, val status: StatusContent, @ColorRes val statusColorRes: Int, @DrawableRes val statusIconRes: Int?, diff --git a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/view/GovernanceLocksView.kt b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/view/GovernanceLocksView.kt index 1738324252..e92a40239d 100644 --- a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/view/GovernanceLocksView.kt +++ b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/view/GovernanceLocksView.kt @@ -53,7 +53,7 @@ class GovernanceLocksView @JvmOverloads constructor( } class GovernanceLocksModel( - val amount: String?, + val amount: CharSequence?, val title: String, val hasUnlockableLocks: Boolean ) diff --git a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/view/NovaChipView.kt b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/view/NovaChipView.kt index 6a9335fa34..fdc2a256af 100644 --- a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/view/NovaChipView.kt +++ b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/view/NovaChipView.kt @@ -221,7 +221,7 @@ class NovaChipView @JvmOverloads constructor( setIconTint(textColorRes) } - fun setText(text: String?) { + fun setText(text: CharSequence?) { chipText.setTextOrHide(text) invalidateDrawablePadding() } @@ -254,4 +254,4 @@ class NovaChipView @JvmOverloads constructor( } } -fun NovaChipView.setTextOrHide(text: String?) = letOrHide(text, ::setText) +fun NovaChipView.setTextOrHide(text: CharSequence?) = letOrHide(text, ::setText) diff --git a/feature-nft-impl/src/main/java/io/novafoundation/nova/feature_nft_impl/presentation/nft/common/model/NftPriceModel.kt b/feature-nft-impl/src/main/java/io/novafoundation/nova/feature_nft_impl/presentation/nft/common/model/NftPriceModel.kt index fc441dd55b..1de2461725 100644 --- a/feature-nft-impl/src/main/java/io/novafoundation/nova/feature_nft_impl/presentation/nft/common/model/NftPriceModel.kt +++ b/feature-nft-impl/src/main/java/io/novafoundation/nova/feature_nft_impl/presentation/nft/common/model/NftPriceModel.kt @@ -1,6 +1,6 @@ package io.novafoundation.nova.feature_nft_impl.presentation.nft.common.model class NftPriceModel( - val amountInfo: String, - val fiat: String? + val amountInfo: CharSequence, + val fiat: CharSequence? ) diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/presentation/staking/main/components/alerts/AlertModel.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/presentation/staking/main/components/alerts/AlertModel.kt index 0db444fc90..321dd94346 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/presentation/staking/main/components/alerts/AlertModel.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/presentation/staking/main/components/alerts/AlertModel.kt @@ -1,8 +1,8 @@ package io.novafoundation.nova.feature_staking_impl.presentation.staking.main.components.alerts class AlertModel( - val title: String, - val extraMessage: String, + val title: CharSequence, + val extraMessage: CharSequence, val type: Type ) { sealed class Type { diff --git a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/presentation/staking/main/components/networkInfo/NetworkInfoItem.kt b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/presentation/staking/main/components/networkInfo/NetworkInfoItem.kt index e7acb4433a..ecc1a9a696 100644 --- a/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/presentation/staking/main/components/networkInfo/NetworkInfoItem.kt +++ b/feature-staking-impl/src/main/java/io/novafoundation/nova/feature_staking_impl/presentation/staking/main/components/networkInfo/NetworkInfoItem.kt @@ -8,7 +8,7 @@ data class NetworkInfoItem(val title: String, val content: ExtendedLoadingState< companion object; - data class Content(val primary: String, val secondary: String?) + data class Content(val primary: CharSequence, val secondary: CharSequence?) } fun NetworkInfoItem.Companion.totalStaked(resourceManager: ResourceManager, content: ExtendedLoadingState): NetworkInfoItem { diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt new file mode 100644 index 0000000000..8db9800eb4 --- /dev/null +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt @@ -0,0 +1,31 @@ +package io.novafoundation.nova.feature_wallet_api.presentation.model + +import android.text.Spannable +import android.text.SpannableStringBuilder +import android.text.style.AbsoluteSizeSpan +import android.text.style.ForegroundColorSpan +import androidx.annotation.DimenRes +import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.common.utils.formatting.toAmountWithFraction +import io.novafoundation.nova.feature_wallet_api.R + +fun CharSequence.formatBalanceWithFraction(resourceManager: ResourceManager, @DimenRes floatAmountSize: Int): CharSequence { + val amountWithFraction = toAmountWithFraction() + + val textColor = resourceManager.getColor(R.color.text_secondary) + val colorSpan = ForegroundColorSpan(textColor) + val sizeSpan = AbsoluteSizeSpan(resourceManager.getDimensionPixelSize(floatAmountSize)) + + return with(amountWithFraction) { + val spannableBuilder = SpannableStringBuilder() + .append(amount) + if (fraction != null) { + spannableBuilder.append(separator + fraction) + val startIndex = amount.length + val endIndex = amount.length + separator.length + fraction!!.length + spannableBuilder.setSpan(colorSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + spannableBuilder.setSpan(sizeSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } + spannableBuilder + } +} diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt index 6a1b87a640..526f7646db 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt @@ -1,5 +1,7 @@ package io.novafoundation.nova.feature_wallet_api.presentation.model +import androidx.annotation.DimenRes +import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.formatting.format import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency import io.novafoundation.nova.feature_wallet_api.domain.model.Asset @@ -11,8 +13,8 @@ import java.math.BigInteger import java.math.RoundingMode data class AmountModel( - val token: String, - val fiat: String? + val token: CharSequence, + val fiat: CharSequence? ) enum class AmountSign(val signSymbol: String) { @@ -96,3 +98,10 @@ fun Asset.transferableFormat() = transferable.formatTokenAmount(token.configurat fun Asset.transferableAmountModel() = mapAmountToAmountModel(transferable, this) fun transferableAmountModelOf(asset: Asset) = mapAmountToAmountModel(asset.transferable, asset) + +fun AmountModel.formatBalanceWithFraction(resourceManager: ResourceManager, @DimenRes floatAmountSize: Int): AmountModel { + return AmountModel( + token = token.formatBalanceWithFraction(resourceManager, floatAmountSize), + fiat = fiat + ) +} diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/PriceSectionView.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/PriceSectionView.kt index c042ab3fbe..bbfa7522ab 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/PriceSectionView.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/PriceSectionView.kt @@ -20,7 +20,7 @@ class PriceSectionView @JvmOverloads constructor( attrs?.let(::applyAttrs) } - fun setPrice(token: String, fiat: String?) { + fun setPrice(token: CharSequence, fiat: CharSequence?) { sectionPriceToken.text = token sectionPriceFiat.setTextOrHide(fiat) } diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/TotalAmountView.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/TotalAmountView.kt index e8dd0edfe5..38048f5bcc 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/TotalAmountView.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/TotalAmountView.kt @@ -29,7 +29,7 @@ class TotalAmountView @JvmOverloads constructor( setAmount(amountModel?.token, amountModel?.fiat) } - fun setAmount(token: String?, fiat: String?) { + fun setAmount(token: CharSequence?, fiat: CharSequence?) { totalAmountToken.text = token totalAmountFiat.text = fiat } From 9c4c60b811ec764b035010a3e98a47ab1853f990 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Mon, 4 Nov 2024 12:03:05 +0100 Subject: [PATCH 52/78] Fixed fallback icon + switch to assets v3 --- common/src/main/res/drawable/ic_nova.xml | 12 +++++++----- runtime/build.gradle | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/common/src/main/res/drawable/ic_nova.xml b/common/src/main/res/drawable/ic_nova.xml index 7c3883474a..3509569d13 100644 --- a/common/src/main/res/drawable/ic_nova.xml +++ b/common/src/main/res/drawable/ic_nova.xml @@ -1,9 +1,11 @@ - + android:viewportWidth="48" + android:viewportHeight="48"> + + + diff --git a/runtime/build.gradle b/runtime/build.gradle index dcf08a110a..06886b75fe 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -14,7 +14,7 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/chains_dev.json\"" - buildConfigField "String", "EVM_ASSETS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/assets/evm/v2/assets_dev.json\"" + buildConfigField "String", "EVM_ASSETS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/assets/evm/v3/assets_dev.json\"" buildConfigField "String", "PRE_CONFIGURED_CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/preConfigured/chains_dev.json\"" buildConfigField "String", "PRE_CONFIGURED_CHAIN_DETAILS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/preConfigured/detailsDev\"" @@ -34,7 +34,7 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/chains.json\"" - buildConfigField "String", "EVM_ASSETS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/assets/evm/v2/assets.json\"" + buildConfigField "String", "EVM_ASSETS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/assets/evm/v3/assets.json\"" buildConfigField "String", "PRE_CONFIGURED_CHAINS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/preConfigured/chains.json\"" buildConfigField "String", "PRE_CONFIGURED_CHAIN_DETAILS_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/chains/v21/preConfigured/details\"" } From 01eacb8742a535540dea202067f4dc9d134eb99f Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Tue, 5 Nov 2024 11:35:59 +0100 Subject: [PATCH 53/78] Operation icons history fix --- .../nova/common/presentation/AssetIconProvider.kt | 2 +- .../view/recyclerview/item/OperationListItem.kt | 1 - common/src/main/res/drawable/ic_receive_history.xml | 9 +++++++++ common/src/main/res/drawable/ic_send_history.xml | 9 +++++++++ common/src/main/res/drawable/ic_staking_history.xml | 10 ++++++++++ common/src/main/res/drawable/ic_swap_history.xml | 12 ++++++++++++ .../src/main/res/layout/item_operation_list_item.xml | 3 ++- .../balance/common/ExpandableAssetsMixin.kt | 3 ++- .../balance/list/di/BalanceListModule.kt | 1 - .../balance/search/AssetSearchViewModel.kt | 2 -- .../balance/search/di/AssetSearchModule.kt | 2 -- .../detail/extrinsic/ExtrinsicDetailViewModel.kt | 3 ++- .../transaction/history/mixin/OperationMappers.kt | 7 +++---- .../main/res/layout/fragment_extrinsic_details.xml | 1 - .../main/res/layout/fragment_pool_reward_details.xml | 3 +-- .../res/layout/fragment_reward_slash_details.xml | 3 +-- .../src/main/res/layout/fragment_swap_details.xml | 3 +-- .../main/res/layout/fragment_transfer_details.xml | 3 +-- 18 files changed, 54 insertions(+), 23 deletions(-) create mode 100644 common/src/main/res/drawable/ic_receive_history.xml create mode 100644 common/src/main/res/drawable/ic_send_history.xml create mode 100644 common/src/main/res/drawable/ic_staking_history.xml create mode 100644 common/src/main/res/drawable/ic_swap_history.xml diff --git a/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt b/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt index a174975a4f..b764abf57e 100644 --- a/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt +++ b/common/src/main/java/io/novafoundation/nova/common/presentation/AssetIconProvider.kt @@ -26,7 +26,7 @@ class RealAssetIconProvider( } override fun getAssetIconOrFallback(iconName: String, iconMode: AssetIconMode): Icon { - val iconUrl = when (assetsIconModeRepository.getIconMode()) { + val iconUrl = when (iconMode) { AssetIconMode.COLORED -> "$coloredBaseUrl/$iconName" AssetIconMode.WHITE -> "$whiteBaseUrl/$iconName" } diff --git a/common/src/main/java/io/novafoundation/nova/common/view/recyclerview/item/OperationListItem.kt b/common/src/main/java/io/novafoundation/nova/common/view/recyclerview/item/OperationListItem.kt index 7a00301eaf..a5f76b4294 100644 --- a/common/src/main/java/io/novafoundation/nova/common/view/recyclerview/item/OperationListItem.kt +++ b/common/src/main/java/io/novafoundation/nova/common/view/recyclerview/item/OperationListItem.kt @@ -60,7 +60,6 @@ class OperationListItem @kotlin.jvm.JvmOverloads constructor( fun setIconStyle(iconStyle: IconStyle) { when (iconStyle) { IconStyle.BORDERED_CIRCLE -> { - icon.setPadding(6.dp) icon.setBackgroundResource(R.drawable.bg_icon_container_on_color) icon.setImageTintRes(R.color.icon_secondary) } diff --git a/common/src/main/res/drawable/ic_receive_history.xml b/common/src/main/res/drawable/ic_receive_history.xml new file mode 100644 index 0000000000..6523824cb6 --- /dev/null +++ b/common/src/main/res/drawable/ic_receive_history.xml @@ -0,0 +1,9 @@ + + + diff --git a/common/src/main/res/drawable/ic_send_history.xml b/common/src/main/res/drawable/ic_send_history.xml new file mode 100644 index 0000000000..255dc6da7d --- /dev/null +++ b/common/src/main/res/drawable/ic_send_history.xml @@ -0,0 +1,9 @@ + + + diff --git a/common/src/main/res/drawable/ic_staking_history.xml b/common/src/main/res/drawable/ic_staking_history.xml new file mode 100644 index 0000000000..e9874f87b4 --- /dev/null +++ b/common/src/main/res/drawable/ic_staking_history.xml @@ -0,0 +1,10 @@ + + + diff --git a/common/src/main/res/drawable/ic_swap_history.xml b/common/src/main/res/drawable/ic_swap_history.xml new file mode 100644 index 0000000000..405a5488c7 --- /dev/null +++ b/common/src/main/res/drawable/ic_swap_history.xml @@ -0,0 +1,12 @@ + + + + diff --git a/common/src/main/res/layout/item_operation_list_item.xml b/common/src/main/res/layout/item_operation_list_item.xml index 7f06bfdb39..11dcd20dc5 100644 --- a/common/src/main/res/layout/item_operation_list_item.xml +++ b/common/src/main/res/layout/item_operation_list_item.xml @@ -14,10 +14,11 @@ android:layout_marginStart="16dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" + android:scaleType="centerCrop" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - tools:src="@drawable/ic_staking_filled" /> + tools:src="@drawable/ic_send_history" /> when (assetesByViewMode) { is AssetsByViewModeResult.ByNetworks -> assetesByViewMode.assets.mapGroupedAssetsToUi(assetIconProvider, currency) - is AssetsByViewModeResult.ByTokens -> assetesByViewMode.tokens.mapGroupedAssetsToUi(assetIconProvider, + is AssetsByViewModeResult.ByTokens -> assetesByViewMode.tokens.mapGroupedAssetsToUi( + assetIconProvider, assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt index ad0985e49b..297571824a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt @@ -11,7 +11,6 @@ import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule -import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt index 4ca31ae8a2..1ceb18ebe1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt @@ -1,8 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.search import io.novafoundation.nova.common.base.BaseViewModel -import io.novafoundation.nova.common.presentation.AssetIconProvider -import io.novafoundation.nova.common.utils.inBackground import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt index 4cfd7ddb97..ef96d43cd7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt @@ -8,13 +8,11 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule -import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ExpandableAssetsMixinFactory import io.novafoundation.nova.feature_assets.presentation.balance.search.AssetSearchViewModel -import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor @Module(includes = [ViewModelModule::class]) class AssetSearchModule { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt index f23d9a1273..30de9d8b79 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/detail/extrinsic/ExtrinsicDetailViewModel.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.feature_assets.presentation.transaction.detail.ex import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.data.model.AssetIconMode import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.presentation.getAssetIconOrFallback import io.novafoundation.nova.common.resources.ResourceManager @@ -55,7 +56,7 @@ class ExtrinsicDetailViewModel( .share() val operationIcon = flowOf { - assetIconProvider.getAssetIconOrFallback(chainAsset().icon) + assetIconProvider.getAssetIconOrFallback(chainAsset().icon, AssetIconMode.WHITE) }.shareInBackground() val content = flowOf { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt index da56fc1fc7..0dae89bf93 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/transaction/history/mixin/OperationMappers.kt @@ -7,7 +7,6 @@ import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import io.novafoundation.nova.common.data.model.AssetIconMode import io.novafoundation.nova.common.presentation.AssetIconProvider -import io.novafoundation.nova.common.presentation.getAssetIconOrFallback import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.buildSpannable import io.novafoundation.nova.common.utils.capitalize @@ -84,7 +83,7 @@ private fun mapStatusToStatusAppearance(status: Operation.Status): OperationStat @DrawableRes private fun transferDirectionIcon(isIncome: Boolean): Int { - return if (isIncome) R.drawable.ic_arrow_down else R.drawable.ic_arrow_up + return if (isIncome) R.drawable.ic_receive_history else R.drawable.ic_send_history } @ColorRes @@ -235,7 +234,7 @@ fun mapOperationToOperationModel( subHeader = resourceManager.getString(subtitleRes), subHeaderEllipsize = TextUtils.TruncateAt.END, statusAppearance = statusAppearance, - operationIcon = resourceManager.getDrawable(R.drawable.ic_staking_filled).asIcon(), + operationIcon = resourceManager.getDrawable(R.drawable.ic_staking_history).asIcon(), ) } @@ -295,7 +294,7 @@ fun mapOperationToOperationModel( statusAppearance = statusAppearance, subHeader = operationType.formatSubHeader(resourceManager), subHeaderEllipsize = TextUtils.TruncateAt.END, - operationIcon = R.drawable.ic_flip_swap.asIcon() + operationIcon = R.drawable.ic_swap_history.asIcon() ) } } diff --git a/feature-assets/src/main/res/layout/fragment_extrinsic_details.xml b/feature-assets/src/main/res/layout/fragment_extrinsic_details.xml index 4b098985a3..23d81a5744 100644 --- a/feature-assets/src/main/res/layout/fragment_extrinsic_details.xml +++ b/feature-assets/src/main/res/layout/fragment_extrinsic_details.xml @@ -35,7 +35,6 @@ android:layout_height="64dp" android:layout_marginTop="16dp" android:background="@drawable/bg_icon_container_on_color" - android:padding="11dp" app:tint="@color/text_secondary" /> + tools:src="@drawable/ic_send_history" /> Date: Tue, 5 Nov 2024 16:12:53 +0100 Subject: [PATCH 54/78] Changed select asset to select networks --- .../list/dynamic/DynamicListBottomSheet.kt | 6 +++ .../feature_wallet_api/data/mappers/Asset.kt | 4 +- .../assetSelector/AssetSelectorProvider.kt | 10 +++- .../view/AssetSelectorBottomSheet.kt | 6 +-- .../main/res/layout/item_asset_selector.xml | 53 +++++++++---------- .../main/res/layout/view_asset_selector.xml | 13 +++-- 6 files changed, 53 insertions(+), 39 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/view/bottomSheet/list/dynamic/DynamicListBottomSheet.kt b/common/src/main/java/io/novafoundation/nova/common/view/bottomSheet/list/dynamic/DynamicListBottomSheet.kt index da5bd6d575..4dd6b54d50 100644 --- a/common/src/main/java/io/novafoundation/nova/common/view/bottomSheet/list/dynamic/DynamicListBottomSheet.kt +++ b/common/src/main/java/io/novafoundation/nova/common/view/bottomSheet/list/dynamic/DynamicListBottomSheet.kt @@ -11,12 +11,14 @@ import androidx.recyclerview.widget.RecyclerView import io.novafoundation.nova.common.R import io.novafoundation.nova.common.utils.DialogExtensions import io.novafoundation.nova.common.utils.WithContextExtensions +import io.novafoundation.nova.common.utils.setTextOrHide import io.novafoundation.nova.common.utils.setVisible import io.novafoundation.nova.common.view.bottomSheet.BaseBottomSheet import kotlinx.android.synthetic.main.bottom_sheet_dynamic_list.dynamicListSheetContent import kotlinx.android.synthetic.main.bottom_sheet_dynamic_list.dynamicListSheetHeader import kotlinx.android.synthetic.main.bottom_sheet_dynamic_list.dynamicListSheetItemContainer import kotlinx.android.synthetic.main.bottom_sheet_dynamic_list.dynamicListSheetRightAction +import kotlinx.android.synthetic.main.bottom_sheet_dynamic_list.dynamicListSheetSubtitle import kotlinx.android.synthetic.main.bottom_sheet_dynamic_list.dynamicListSheetTitle typealias ClickHandler = (BaseDynamicListBottomSheet, T) -> Unit @@ -56,6 +58,10 @@ abstract class BaseDynamicListBottomSheet(context: Context) : dynamicListSheetTitle.text = title } + fun setSubtitle(subtitle: CharSequence?) { + dynamicListSheetSubtitle.setTextOrHide(subtitle) + } + final override fun setTitle(titleId: Int) { dynamicListSheetTitle.setText(titleId) } diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt index 09e8bf058b..481432c072 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/data/mappers/Asset.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.feature_wallet_api.data.mappers import androidx.annotation.StringRes import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager +import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback import io.novafoundation.nova.feature_wallet_api.R import io.novafoundation.nova.feature_wallet_api.domain.model.Asset @@ -14,6 +15,7 @@ fun mapAssetToAssetModel( assetIconProvider: AssetIconProvider, asset: Asset, resourceManager: ResourceManager, + icon: Icon = assetIconProvider.getAssetIconOrFallback(asset.token.configuration), retrieveAmount: (Asset) -> BigDecimal = Asset::transferable, @StringRes patternId: Int? = R.string.common_available_format ): AssetModel { @@ -24,7 +26,7 @@ fun mapAssetToAssetModel( AssetModel( chainId = asset.token.configuration.chainId, chainAssetId = asset.token.configuration.id, - icon = assetIconProvider.getAssetIconOrFallback(token.configuration), + icon = icon, tokenName = token.configuration.name, tokenSymbol = token.configuration.symbol.value, assetBalance = formattedAmount diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/assetSelector/AssetSelectorProvider.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/assetSelector/AssetSelectorProvider.kt index 0c08903e45..ecc5d7bdff 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/assetSelector/AssetSelectorProvider.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/mixin/assetSelector/AssetSelectorProvider.kt @@ -6,6 +6,7 @@ import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.Event import io.novafoundation.nova.common.utils.WithCoroutineScopeExtensions import io.novafoundation.nova.common.view.bottomSheet.list.dynamic.DynamicListBottomSheet +import io.novafoundation.nova.feature_account_api.presenatation.chain.iconOrFallback import io.novafoundation.nova.feature_wallet_api.data.mappers.mapAssetToAssetModel import io.novafoundation.nova.feature_wallet_api.domain.SelectableAssetAndOption import io.novafoundation.nova.feature_wallet_api.domain.SelectableAssetUseCase @@ -82,7 +83,14 @@ private class AssetSelectorProvider( } private fun mapAssetAndOptionToSelectorModel(assetAndOption: SelectableAssetAndOption): AssetSelectorModel { - val assetModel = mapAssetToAssetModel(assetIconProvider, assetAndOption.asset, resourceManager, patternId = null, retrieveAmount = amountProvider) + val assetModel = mapAssetToAssetModel( + assetIconProvider, + assetAndOption.asset, + resourceManager, + icon = assetAndOption.option.assetWithChain.chain.iconOrFallback(), + patternId = null, + retrieveAmount = amountProvider + ) val title = assetAndOption.formatTitle() return AssetSelectorModel(assetModel, title, assetAndOption.option.additional.identifier) diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt index 40d51d6954..7e382e1267 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt @@ -7,7 +7,6 @@ import androidx.recyclerview.widget.DiffUtil import coil.ImageLoader import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.inflateChild -import io.novafoundation.nova.common.utils.setVisible import io.novafoundation.nova.common.view.bottomSheet.list.dynamic.ClickHandler import io.novafoundation.nova.common.view.bottomSheet.list.dynamic.DynamicListBottomSheet import io.novafoundation.nova.common.view.bottomSheet.list.dynamic.DynamicListSheetAdapter @@ -15,8 +14,8 @@ import io.novafoundation.nova.common.view.bottomSheet.list.dynamic.HolderCreator import io.novafoundation.nova.feature_wallet_api.R import io.novafoundation.nova.feature_wallet_api.presentation.mixin.assetSelector.AssetSelectorModel import kotlinx.android.synthetic.main.item_asset_selector.view.itemAssetSelectorBalance -import kotlinx.android.synthetic.main.item_asset_selector.view.itemAssetSelectorCheckmark import kotlinx.android.synthetic.main.item_asset_selector.view.itemAssetSelectorIcon +import kotlinx.android.synthetic.main.item_asset_selector.view.itemAssetSelectorRadioButton import kotlinx.android.synthetic.main.item_asset_selector.view.itemAssetSelectorTokenName class AssetSelectorBottomSheet( @@ -35,6 +34,7 @@ class AssetSelectorBottomSheet( super.onCreate(savedInstanceState) setTitle(R.string.wallet_assets) + setSubtitle(null) } override fun holderCreator(): HolderCreator = { parent -> @@ -58,7 +58,7 @@ private class AssetSelectorHolder( itemAssetSelectorBalance.text = item.assetModel.assetBalance itemAssetSelectorTokenName.text = item.title itemAssetSelectorIcon.setIcon(item.assetModel.icon, imageLoader) - itemAssetSelectorCheckmark.setVisible(isSelected, falseState = View.INVISIBLE) + itemAssetSelectorRadioButton.isChecked = isSelected } } } diff --git a/feature-wallet-api/src/main/res/layout/item_asset_selector.xml b/feature-wallet-api/src/main/res/layout/item_asset_selector.xml index 4638007d73..01dd050e53 100644 --- a/feature-wallet-api/src/main/res/layout/item_asset_selector.xml +++ b/feature-wallet-api/src/main/res/layout/item_asset_selector.xml @@ -7,37 +7,31 @@ android:background="@drawable/bg_primary_list_item" tools:background="@color/secondary_screen_background"> - - + tools:src="@drawable/ic_fallback_network_icon" /> @@ -45,24 +39,29 @@ - + app:layout_constraintTop_toTopOf="parent" /> \ No newline at end of file diff --git a/feature-wallet-api/src/main/res/layout/view_asset_selector.xml b/feature-wallet-api/src/main/res/layout/view_asset_selector.xml index d69a6ce5e5..c6e045a5dd 100644 --- a/feature-wallet-api/src/main/res/layout/view_asset_selector.xml +++ b/feature-wallet-api/src/main/res/layout/view_asset_selector.xml @@ -9,16 +9,15 @@ + tools:src="@drawable/ic_fallback_network_icon" /> Date: Wed, 6 Nov 2024 10:05:42 +0100 Subject: [PATCH 55/78] Fixed swap crash --- .../presentation/flow/asset/AssetFlowViewModel.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index 124e1ab81f..e60d393abd 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -56,16 +56,15 @@ abstract class AssetFlowViewModel( protected val externalBalancesFlow = externalBalancesInteractor.observeExternalBalances() - private val searchAssetsFlow = flowOfAll { searchAssetsFlow() } - .shareInBackground() + private val searchAssetsFlow = flowOfAll { searchAssetsFlow() } // lazy use searchAssetsFlow to let subclasses initialize self + .shareInBackground(SharingStarted.Lazily) val searchResults = combine( - searchAssetsFlow, // lazy use searchAssetsFlow to let subclasses initialize self + searchAssetsFlow, selectedCurrency, ) { assets, currency -> mapAssets(assets, currency) }.distinctUntilChanged() - .shareInBackground(SharingStarted.Lazily) val placeholder = searchAssetsFlow.map { getPlaceholder(query.value, it.groupList()) } From de5c762b515d992795dfd3dfd7a91fb4df1be70e Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Wed, 6 Nov 2024 10:47:24 +0100 Subject: [PATCH 56/78] Fixed swap navigation --- .../nova/app/root/navigation/Navigator.kt | 9 ++++ .../main/res/navigation/main_nav_graph.xml | 24 ++-------- .../res/navigation/start_swap_nav_graph.xml | 9 ++-- .../main/res/navigation/swap_flow_graph.xml | 47 +++++++++++++++++++ .../presentation/AssetsRouter.kt | 2 + .../swap/executor/ReselectSwapFlowExecutor.kt | 3 +- 6 files changed, 66 insertions(+), 28 deletions(-) create mode 100644 app/src/main/res/navigation/swap_flow_graph.xml diff --git a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt index 530e524344..a201808540 100644 --- a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt +++ b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt @@ -403,6 +403,15 @@ class Navigator( navController?.navigate(R.id.action_buyFlow_to_buyFlowNetwork, NetworkFlowFragment.createPayload(payload)) } + override fun backFromSwapFlow() { + performNavigation( + cases = arrayOf( + R.id.swapFlowFragment to R.id.action_back_swapFlowFragment, + R.id.swapFlowNetworkFragment to R.id.action_back_swapFlowNetworkFragment + ) + ) + } + override fun openSwapFlow() { val payload = SwapFlowPayload.InitialSelecting navController?.navigate(R.id.action_mainFragment_to_swapFlow, AssetSwapFlowFragment.getBundle(payload)) diff --git a/app/src/main/res/navigation/main_nav_graph.xml b/app/src/main/res/navigation/main_nav_graph.xml index 61b7ba21ca..24c4169c17 100644 --- a/app/src/main/res/navigation/main_nav_graph.xml +++ b/app/src/main/res/navigation/main_nav_graph.xml @@ -479,7 +479,7 @@ - - - - - - - - + + \ No newline at end of file diff --git a/app/src/main/res/navigation/start_swap_nav_graph.xml b/app/src/main/res/navigation/start_swap_nav_graph.xml index 2ded44e48d..9577fda503 100644 --- a/app/src/main/res/navigation/start_swap_nav_graph.xml +++ b/app/src/main/res/navigation/start_swap_nav_graph.xml @@ -20,7 +20,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/navigation/swap_flow_graph.xml b/app/src/main/res/navigation/swap_flow_graph.xml new file mode 100644 index 0000000000..9b549cca9c --- /dev/null +++ b/app/src/main/res/navigation/swap_flow_graph.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt index 8c1be6cfeb..d15ac530a5 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt @@ -83,4 +83,6 @@ interface AssetsRouter { fun openSwapNetworks(payload: NetworkSwapFlowPayload) fun openBuyNetworks(payload: NetworkFlowPayload) + + fun backFromSwapFlow() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/ReselectSwapFlowExecutor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/ReselectSwapFlowExecutor.kt index 7d89f5540f..51176c8542 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/ReselectSwapFlowExecutor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/ReselectSwapFlowExecutor.kt @@ -21,6 +21,7 @@ class ReselectSwapFlowExecutor( SelectingDirection.IN -> state.setAssetInUpdatingFee(chainAsset) SelectingDirection.OUT -> state.setAssetOut(chainAsset) } - assetsRouter.back() + + assetsRouter.backFromSwapFlow() } } From 7b401e5719aa2fea4e44a14a45dc8fdb1ced9940 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 7 Nov 2024 09:24:37 +0100 Subject: [PATCH 57/78] Fixed space between items + fixed animation glitch --- .../novafoundation/nova/common/utils/images/Icon.kt | 6 +++--- .../presentation/balance/common/AssetListMixin.kt | 3 +-- .../balance/common/AssetTokensDecoration.kt | 11 ++++++++--- .../balance/common/ExpandableAssetsMixin.kt | 3 ++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/images/Icon.kt b/common/src/main/java/io/novafoundation/nova/common/utils/images/Icon.kt index 931caf803f..1f78a20199 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/images/Icon.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/images/Icon.kt @@ -11,11 +11,11 @@ import io.novafoundation.nova.common.utils.makeVisible sealed class Icon { - class FromLink(val data: String) : Icon() + data class FromLink(val data: String) : Icon() - class FromDrawable(val data: Drawable) : Icon() + data class FromDrawable(val data: Drawable) : Icon() - class FromDrawableRes(@DrawableRes val res: Int) : Icon() + data class FromDrawableRes(@DrawableRes val res: Int) : Icon() } typealias ExtraImageRequestBuilding = ImageRequest.Builder.() -> Unit diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index aca876dbb8..f6e21824d5 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -77,8 +77,7 @@ class RealAssetListMixin( AssetViewMode.NETWORKS -> walletInteractor.groupAssetsByNetwork(assets, externalBalances).byNetworks() AssetViewMode.TOKENS -> walletInteractor.groupAssetsByToken(assets, externalBalances).byTokens() } - }.distinctUntilChanged() - .shareInBackground() + }.shareInBackground() private val expandableAssetsMixin = expandableAssetsMixinFactory.create(assetsByViewMode) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt index 595937b295..c82acfaeef 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt @@ -27,7 +27,7 @@ import kotlin.math.roundToInt class AssetTokensDecoration( private val context: Context, - adapter: ExpandableAdapter, + private val adapter: ExpandableAdapter, animator: ExpandableAnimator ) : ExpandableItemDecoration( adapter, @@ -60,9 +60,14 @@ class AssetTokensDecoration( override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { val viewHolder = parent.getChildViewHolder(view) + if (viewHolder.bindingAdapterPosition == 0) return + if (viewHolder is TokenAssetGroupViewHolder) { - outRect.set(0, 12.dp(context), 0, 0) - return + if (viewHolder.bindingAdapterPosition == adapter.getItems().size - 1) { + outRect.set(0, 12.dp(context), 0, 12.dp(context)) + } else { + outRect.set(0, 12.dp(context), 0, 0) + } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt index bfbcf8dd69..8cb12a9aa3 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -14,6 +14,7 @@ import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged class ExpandableAssetsMixinFactory( private val assetIconProvider: AssetIconProvider, @@ -58,7 +59,7 @@ class RealExpandableAssetsMixin( assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } ) } - } + }.distinctUntilChanged() override fun expandToken(tokenGroupUi: TokenGroupUi) { expandedTokenIdsFlow.updateValue { it.toggle(tokenGroupUi.itemId) } From 09aecd9f16cb66931ba1208a12c5fe1f7a6b6cc9 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 7 Nov 2024 09:36:43 +0100 Subject: [PATCH 58/78] Bump white icons link --- common/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/build.gradle b/common/build.gradle index 7b2dfa6b78..fa5059f0cb 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -44,7 +44,7 @@ android { buildConfigField "String", "APP_UPDATE_SOURCE_LINK", "\"https://play.google.com/store/apps/details?id=io.novafoundation.nova.market\"" buildConfigField "String", "ASSET_COLORED_ICON_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/icons/tokens/colored\"" - buildConfigField "String", "ASSET_WHITE_ICON_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/icons/tokens/white\"" + buildConfigField "String", "ASSET_WHITE_ICON_URL", "\"https://raw.githubusercontent.com/novasamatech/nova-utils/master/icons/tokens/white/v1\"" } buildTypes { From 92aace445c968513e36279edad4bc91df81b6fac Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 7 Nov 2024 09:38:19 +0100 Subject: [PATCH 59/78] Run ktlint --- .../feature_assets/presentation/balance/common/AssetListMixin.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index f6e21824d5..4f247cc3d1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -15,7 +15,6 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.distinctUntilChanged class AssetListMixinFactory( private val walletInteractor: WalletInteractor, From 35920d1d6dce49907015435b4b771239e774806f Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 7 Nov 2024 10:17:48 +0100 Subject: [PATCH 60/78] Fixed pr notes --- .../feature_assets/di/AssetsFeatureModule.kt | 16 +++++-- .../balance/common/ExpandableAssetsMixin.kt | 14 +++--- .../common/mappers/AssetMappersCommon.kt | 6 +-- .../common/mappers/NetworkAssetMappers.kt | 10 ++-- .../common/mappers/TokenAssetMappers.kt | 22 ++++----- .../balance/list/BalanceListViewModel.kt | 6 ++- .../balance/list/di/BalanceListModule.kt | 8 ++-- .../balance/search/AssetSearchViewModel.kt | 2 - .../balance/search/di/AssetSearchModule.kt | 2 - .../buy/flow/asset/AssetBuyFlowViewModel.kt | 7 ++- .../buy/flow/asset/di/AssetBuyFlowModule.kt | 7 ++- .../flow/asset/AssetFlowViewModel.kt | 8 ++-- .../flow/asset/AssetReceiveFlowViewModel.kt | 7 ++- .../flow/asset/di/AssetReceiveFlowModule.kt | 7 ++- .../send/flow/asset/AssetSendFlowViewModel.kt | 11 +++-- .../send/flow/asset/di/AssetSendFlowModule.kt | 7 ++- .../swap/asset/AssetSwapFlowViewModel.kt | 11 +++-- .../swap/asset/di/AssetSwapFlowModule.kt | 7 ++- .../presentation/model/AmountFormatters.kt | 48 ++++++++++++------- .../presentation/model/AmountModel.kt | 5 +- 20 files changed, 129 insertions(+), 82 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt index cba554bc5e..1e7a4e6eb6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureModule.kt @@ -48,6 +48,8 @@ import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.updaters import io.novafoundation.nova.feature_wallet_api.data.repository.ExternalBalanceRepository import io.novafoundation.nova.feature_wallet_api.domain.interfaces.CoinPriceRepository import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletRepository +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter +import io.novafoundation.nova.feature_wallet_api.presentation.model.RealAmountFormatter import io.novafoundation.nova.runtime.ethereum.StorageSharedRequestsBuilderFactory import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry @@ -186,19 +188,25 @@ class AssetsFeatureModule { return SwapFlowExecutorFactory(initialSwapFlowExecutor, assetsRouter, swapSettingsStateProvider) } + @Provides + @FeatureScope + fun provideAmountFormatter(resourceManager: ResourceManager): AmountFormatter { + return RealAmountFormatter(resourceManager) + } + @Provides @FeatureScope fun provideExpandableAssetsMixinFactory( - resourceManager: ResourceManager, assetIconProvider: AssetIconProvider, currencyInteractor: CurrencyInteractor, - assetsViewModeRepository: AssetsViewModeRepository + assetsViewModeRepository: AssetsViewModeRepository, + amountFormatter: AmountFormatter ): ExpandableAssetsMixinFactory { return ExpandableAssetsMixinFactory( - resourceManager, assetIconProvider, currencyInteractor, - assetsViewModeRepository + assetsViewModeRepository, + amountFormatter ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt index 88019b4b11..56c628f3b1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -2,7 +2,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common import io.novafoundation.nova.common.data.model.switch import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository -import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.utils.toggle import io.novafoundation.nova.common.utils.updateValue @@ -12,19 +11,20 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.ite import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine class ExpandableAssetsMixinFactory( - private val resourceManager: ResourceManager, private val assetIconProvider: AssetIconProvider, private val currencyInteractor: CurrencyInteractor, - private val assetsViewModeRepository: AssetsViewModeRepository + private val assetsViewModeRepository: AssetsViewModeRepository, + private val amountFormatter: AmountFormatter ) { fun create(assetsFlow: Flow): ExpandableAssetsMixin { - return RealExpandableAssetsMixin(resourceManager, assetsFlow, currencyInteractor, assetIconProvider, assetsViewModeRepository) + return RealExpandableAssetsMixin(assetsFlow, currencyInteractor, assetIconProvider, assetsViewModeRepository, amountFormatter) } } @@ -38,11 +38,11 @@ interface ExpandableAssetsMixin { } class RealExpandableAssetsMixin( - private val resourceManager: ResourceManager, assetsFlow: Flow, currencyInteractor: CurrencyInteractor, private val assetIconProvider: AssetIconProvider, private val assetsViewModeRepository: AssetsViewModeRepository, + private val amountFormatter: AmountFormatter ) : ExpandableAssetsMixin { private val selectedCurrency = currencyInteractor.observeSelectCurrency() @@ -55,9 +55,9 @@ class RealExpandableAssetsMixin( selectedCurrency ) { assetesByViewMode, expandedTokens, currency -> when (assetesByViewMode) { - is AssetsByViewModeResult.ByNetworks -> assetesByViewMode.assets.mapGroupedAssetsToUi(resourceManager, assetIconProvider, currency) + is AssetsByViewModeResult.ByNetworks -> assetesByViewMode.assets.mapGroupedAssetsToUi(amountFormatter, assetIconProvider, currency) is AssetsByViewModeResult.ByTokens -> assetesByViewMode.tokens.mapGroupedAssetsToUi( - resourceManager = resourceManager, + amountFormatter = amountFormatter, assetIconProvider = assetIconProvider, assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt index 28abb0848b..488f2fc06e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/AssetMappersCommon.kt @@ -1,7 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mappers import androidx.annotation.ColorRes -import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.formatting.formatAsChange import io.novafoundation.nova.common.utils.isNonNegative import io.novafoundation.nova.common.utils.isZero @@ -15,6 +14,7 @@ import io.novafoundation.nova.feature_currency_api.presentation.formatters.forma import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.domain.model.CoinRateChange import io.novafoundation.nova.feature_wallet_api.domain.model.Token +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import io.novafoundation.nova.feature_wallet_api.presentation.model.formatBalanceWithFraction import io.novafoundation.nova.feature_wallet_api.presentation.model.mapAmountToAmountModel import java.math.BigDecimal @@ -25,7 +25,7 @@ fun mapCoinRateChange(coinRateChange: CoinRateChange?, currency: Currency): Stri } fun mapAssetToAssetModel( - resourceManager: ResourceManager, + amountFormatter: AmountFormatter, asset: Asset, balance: PricedAmount ): AssetModel { @@ -35,7 +35,7 @@ fun mapAssetToAssetModel( amount = balance.amount, asset = asset, includeAssetTicker = false - ).formatBalanceWithFraction(resourceManager, R.dimen.asset_balance_fraction_size) + ).formatBalanceWithFraction(amountFormatter, R.dimen.asset_balance_fraction_size) ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt index f5ac180e40..e66fb4a8cb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/NetworkAssetMappers.kt @@ -2,7 +2,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mapper import io.novafoundation.nova.common.list.GroupedList import io.novafoundation.nova.common.list.toListWithHeaders -import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback @@ -15,30 +14,31 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.ite import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkGroupUi import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import java.math.BigDecimal fun GroupedList.mapGroupedAssetsToUi( - resourceManager: ResourceManager, + amountFormatter: AmountFormatter, assetIconProvider: AssetIconProvider, currency: Currency, groupBalance: (NetworkAssetGroup) -> BigDecimal = NetworkAssetGroup::groupTotalBalanceFiat, balance: (AssetBalance) -> PricedAmount = AssetBalance::total, ): List { return mapKeys { (assetGroup, _) -> mapAssetGroupToUi(assetGroup, currency, groupBalance) } - .mapValues { (_, assets) -> mapAssetsToAssetModels(resourceManager, assetIconProvider, assets, balance) } + .mapValues { (_, assets) -> mapAssetsToAssetModels(amountFormatter, assetIconProvider, assets, balance) } .toListWithHeaders() .filterIsInstance() } private fun mapAssetsToAssetModels( - resourceManager: ResourceManager, + amountFormatter: AmountFormatter, assetIconProvider: AssetIconProvider, assets: List, balance: (AssetBalance) -> PricedAmount ): List { return assets.map { NetworkAssetUi( - mapAssetToAssetModel(resourceManager, it.asset, balance(it.balanceWithOffchain)), + mapAssetToAssetModel(amountFormatter, it.asset, balance(it.balanceWithOffchain)), assetIconProvider.getAssetIconOrFallback(it.asset.token.configuration) ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index 295b5ef5ca..7e13ddad55 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -2,7 +2,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.mapper import io.novafoundation.nova.common.list.GroupedList import io.novafoundation.nova.common.list.toListWithHeaders -import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.presentation.getAssetIconOrFallback import io.novafoundation.nova.common.utils.formatTokenAmount @@ -19,19 +18,20 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.ite import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel import io.novafoundation.nova.feature_wallet_api.presentation.model.formatBalanceWithFraction fun GroupedList.mapGroupedAssetsToUi( - resourceManager: ResourceManager, + amountFormatter: AmountFormatter, assetIconProvider: AssetIconProvider, assetFilter: (groupId: String, List) -> List = { _, assets -> assets }, groupBalance: (TokenAssetGroup) -> PricedAmount = { it.groupBalance.total }, balance: (AssetBalance) -> PricedAmount = AssetBalance::total, ): List { - return mapKeys { (group, assets) -> mapTokenAssetGroupToUi(resourceManager, assetIconProvider, group, assets, groupBalance) } + return mapKeys { (group, assets) -> mapTokenAssetGroupToUi(amountFormatter, assetIconProvider, group, assets, groupBalance) } .mapValues { (group, assets) -> - val assetModels = mapAssetsToAssetModels(resourceManager, assetIconProvider, group, assets, balance) + val assetModels = mapAssetsToAssetModels(amountFormatter, assetIconProvider, group, assets, balance) assetFilter(group.itemId, assetModels) } .toListWithHeaders() @@ -39,7 +39,7 @@ fun GroupedList.mapGroupedAssetsToUi( } fun mapTokenAssetGroupToUi( - resourceManager: ResourceManager, + amountFormatter: AmountFormatter, assetIconProvider: AssetIconProvider, assetGroup: TokenAssetGroup, assets: List, @@ -57,13 +57,13 @@ fun mapTokenAssetGroupToUi( balance = AmountModel( token = balance.amount.formatTokenAmount(), fiat = balance.fiat.formatAsCurrency(assetGroup.token.currency) - ).formatBalanceWithFraction(resourceManager, R.dimen.asset_balance_fraction_size), - groupType = mapType(resourceManager, assetGroup, assets, groupBalance) + ).formatBalanceWithFraction(amountFormatter, R.dimen.asset_balance_fraction_size), + groupType = mapType(amountFormatter, assetGroup, assets, groupBalance) ) } private fun mapAssetsToAssetModels( - resourceManager: ResourceManager, + amountFormatter: AmountFormatter, assetIconProvider: AssetIconProvider, group: TokenGroupUi, assets: List, @@ -72,7 +72,7 @@ private fun mapAssetsToAssetModels( return assets.map { TokenAssetUi( group.getId(), - mapAssetToAssetModel(resourceManager, it.asset, balance(it.balanceWithOffChain)), + mapAssetToAssetModel(amountFormatter, it.asset, balance(it.balanceWithOffChain)), assetIconProvider.getAssetIconOrFallback(it.asset.token.configuration), mapChainToUi(it.chain) ) @@ -80,14 +80,14 @@ private fun mapAssetsToAssetModels( } private fun mapType( - resourceManager: ResourceManager, + amountFormatter: AmountFormatter, assetGroup: TokenAssetGroup, assets: List, groupBalance: (TokenAssetGroup) -> PricedAmount ): TokenGroupUi.GroupType { return if (assets.size == 1) { val balance = groupBalance(assetGroup) - TokenGroupUi.GroupType.SingleItem(mapAssetToAssetModel(resourceManager, assets.first().asset, balance)) + TokenGroupUi.GroupType.SingleItem(mapAssetToAssetModel(amountFormatter, assets.first().asset, balance)) } else { TokenGroupUi.GroupType.Group } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt index 95f4991440..c6d8d940ff 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt @@ -36,6 +36,7 @@ import io.novafoundation.nova.feature_currency_api.presentation.formatters.simpl import io.novafoundation.nova.feature_nft_api.data.model.Nft import io.novafoundation.nova.feature_swap_api.domain.interactor.SwapAvailabilityInteractor import io.novafoundation.nova.feature_wallet_api.presentation.formatters.mapBalanceIdToUi +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_wallet_api.presentation.model.mapAmountToAmountModel import io.novafoundation.nova.feature_wallet_connect_api.domain.sessions.WalletConnectSessionsUseCase @@ -68,7 +69,8 @@ class BalanceListViewModel( private val resourceManager: ResourceManager, private val walletConnectSessionsUseCase: WalletConnectSessionsUseCase, private val swapAvailabilityInteractor: SwapAvailabilityInteractor, - private val assetListMixinFactory: AssetListMixinFactory + private val assetListMixinFactory: AssetListMixinFactory, + private val amountFormatter: AmountFormatter ) : BaseViewModel() { private val _hideRefreshEvent = MutableLiveData>() @@ -126,7 +128,7 @@ class BalanceListViewModel( val currency = selectedCurrency.first() TotalBalanceModel( isBreakdownAbailable = breakdown.breakdown.isNotEmpty(), - totalBalanceFiat = breakdown.total.simpleFormatAsCurrency(currency).formatBalanceWithFraction(resourceManager, R.dimen.total_balance_fraction_size), + totalBalanceFiat = breakdown.total.simpleFormatAsCurrency(currency).formatBalanceWithFraction(amountFormatter, R.dimen.total_balance_fraction_size), lockedBalanceFiat = breakdown.locksTotal.amount.formatAsCurrency(currency), enableSwap = swapSupported ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt index ad0985e49b..ef025d8cab 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt @@ -11,7 +11,6 @@ import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.di.scope.ScreenScope import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule -import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -28,6 +27,7 @@ import io.novafoundation.nova.feature_nft_api.data.repository.NftRepository import io.novafoundation.nova.feature_swap_api.domain.interactor.SwapAvailabilityInteractor import io.novafoundation.nova.feature_wallet_api.data.repository.BalanceHoldsRepository import io.novafoundation.nova.feature_wallet_api.data.repository.BalanceLocksRepository +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import io.novafoundation.nova.feature_wallet_connect_api.domain.sessions.WalletConnectSessionsUseCase @Module(includes = [ViewModelModule::class]) @@ -85,7 +85,8 @@ class BalanceListModule { resourceManager: ResourceManager, walletConnectSessionsUseCase: WalletConnectSessionsUseCase, swapAvailabilityInteractor: SwapAvailabilityInteractor, - assetListMixinFactory: AssetListMixinFactory + assetListMixinFactory: AssetListMixinFactory, + amountFormatter: AmountFormatter ): ViewModel { return BalanceListViewModel( walletInteractor = walletInteractor, @@ -97,7 +98,8 @@ class BalanceListModule { resourceManager = resourceManager, walletConnectSessionsUseCase = walletConnectSessionsUseCase, swapAvailabilityInteractor = swapAvailabilityInteractor, - assetListMixinFactory = assetListMixinFactory + assetListMixinFactory = assetListMixinFactory, + amountFormatter = amountFormatter ) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt index 4ca31ae8a2..1ceb18ebe1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt @@ -1,8 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.search import io.novafoundation.nova.common.base.BaseViewModel -import io.novafoundation.nova.common.presentation.AssetIconProvider -import io.novafoundation.nova.common.utils.inBackground import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt index 4cfd7ddb97..ef96d43cd7 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/di/AssetSearchModule.kt @@ -8,13 +8,11 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule -import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInteractorFactory import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ExpandableAssetsMixinFactory import io.novafoundation.nova.feature_assets.presentation.balance.search.AssetSearchViewModel -import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor @Module(includes = [ViewModelModule::class]) class AssetSearchModule { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt index b035823fc2..7d194ab31d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt @@ -14,6 +14,7 @@ import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFl import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import kotlinx.coroutines.flow.Flow class AssetBuyFlowViewModel( @@ -25,7 +26,8 @@ class AssetBuyFlowViewModel( accountUseCase: SelectedAccountUseCase, buyMixinFactory: BuyMixin.Factory, resourceManager: ResourceManager, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + amountFormatter: AmountFormatter ) : AssetFlowViewModel( interactorFactory, router, @@ -34,7 +36,8 @@ class AssetBuyFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, - assetIconProvider + assetIconProvider, + amountFormatter ) { val buyMixin = buyMixinFactory.create(scope = this) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt index fe132b056e..03058803f4 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt @@ -18,6 +18,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.Control import io.novafoundation.nova.feature_assets.presentation.buy.flow.asset.AssetBuyFlowViewModel import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter @Module(includes = [ViewModelModule::class]) class AssetBuyFlowModule { @@ -39,7 +40,8 @@ class AssetBuyFlowModule { accountUseCase: SelectedAccountUseCase, buyMixinFactory: BuyMixin.Factory, resourceManager: ResourceManager, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + amountFormatter: AmountFormatter ): ViewModel { return AssetBuyFlowViewModel( interactorFactory = interactorFactory, @@ -50,7 +52,8 @@ class AssetBuyFlowModule { accountUseCase = accountUseCase, buyMixinFactory = buyMixinFactory, resourceManager = resourceManager, - assetIconProvider = assetIconProvider + assetIconProvider = assetIconProvider, + amountFormatter = amountFormatter ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index aa84e30b7f..43a23f288a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -25,6 +25,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.ite import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -41,7 +42,8 @@ abstract class AssetFlowViewModel( protected val accountUseCase: SelectedAccountUseCase, externalBalancesInteractor: ExternalBalancesInteractor, protected val resourceManager: ResourceManager, - private val assetIconProvider: AssetIconProvider + private val assetIconProvider: AssetIconProvider, + private val amountFormatter: AmountFormatter ) : BaseViewModel() { protected val interactor = interactorFactory.createByAssetViewMode() @@ -87,11 +89,11 @@ abstract class AssetFlowViewModel( } open fun mapNetworkAssets(assets: Map>, currency: Currency): List { - return assets.mapGroupedAssetsToUi(resourceManager, assetIconProvider, currency) + return assets.mapGroupedAssetsToUi(amountFormatter, assetIconProvider, currency) } open fun mapTokensAssets(assets: Map>): List { - return assets.map { mapTokenAssetGroupToUi(resourceManager, assetIconProvider, it.key, assets = it.value) } + return assets.map { mapTokenAssetGroupToUi(amountFormatter, assetIconProvider, it.key, assets = it.value) } } internal fun validate(assetModel: AssetModel, onAccept: (AssetModel) -> Unit) { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt index 41242fac2d..3b4911dfdc 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt @@ -14,6 +14,7 @@ import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowVi import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import kotlinx.coroutines.flow.Flow class AssetReceiveFlowViewModel( @@ -24,7 +25,8 @@ class AssetReceiveFlowViewModel( controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + amountFormatter: AmountFormatter ) : AssetFlowViewModel( interactorFactory, router, @@ -33,7 +35,8 @@ class AssetReceiveFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, - assetIconProvider + assetIconProvider, + amountFormatter ) { override fun searchAssetsFlow(): Flow { return interactor.searchReceiveAssetsFlow(query, externalBalancesFlow) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt index aab728526b..6356005bd3 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt @@ -17,6 +17,7 @@ import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.receive.flow.asset.AssetReceiveFlowViewModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter @Module(includes = [ViewModelModule::class]) class AssetReceiveFlowModule { @@ -37,7 +38,8 @@ class AssetReceiveFlowModule { controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + amountFormatter: AmountFormatter ): ViewModel { return AssetReceiveFlowViewModel( interactorFactory = interactorFactory, @@ -47,7 +49,8 @@ class AssetReceiveFlowModule { controllableAssetCheck = controllableAssetCheck, accountUseCase = accountUseCase, resourceManager = resourceManager, - assetIconProvider = assetIconProvider + assetIconProvider = assetIconProvider, + amountFormatter = amountFormatter ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt index e26fe5544d..2fc68d6940 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt @@ -25,6 +25,7 @@ import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import kotlinx.coroutines.flow.Flow @@ -36,7 +37,8 @@ class AssetSendFlowViewModel( controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, - private val assetIconProvider: AssetIconProvider + private val assetIconProvider: AssetIconProvider, + private val amountFormatter: AmountFormatter ) : AssetFlowViewModel( interactorFactory, router, @@ -45,7 +47,8 @@ class AssetSendFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, - assetIconProvider + assetIconProvider, + amountFormatter ) { override fun searchAssetsFlow(): Flow { @@ -68,7 +71,7 @@ class AssetSendFlowViewModel( override fun mapNetworkAssets(assets: Map>, currency: Currency): List { return assets.mapGroupedAssetsToUi( - resourceManager, + amountFormatter, assetIconProvider, currency, NetworkAssetGroup::groupTransferableBalanceFiat, @@ -78,7 +81,7 @@ class AssetSendFlowViewModel( override fun mapTokensAssets(assets: Map>): List { return assets.map { (group, assets) -> - mapTokenAssetGroupToUi(resourceManager, assetIconProvider, group, assets = assets) { it.groupBalance.transferable } + mapTokenAssetGroupToUi(amountFormatter, assetIconProvider, group, assets = assets) { it.groupBalance.transferable } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt index 45f08cb0c9..8d6b368766 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt @@ -17,6 +17,7 @@ import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ControllableAssetCheckMixin import io.novafoundation.nova.feature_assets.presentation.send.flow.asset.AssetSendFlowViewModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter @Module(includes = [ViewModelModule::class]) class AssetSendFlowModule { @@ -37,7 +38,8 @@ class AssetSendFlowModule { controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + amountFormatter: AmountFormatter ): ViewModel { return AssetSendFlowViewModel( interactorFactory = interactorFactory, @@ -47,7 +49,8 @@ class AssetSendFlowModule { controllableAssetCheck = controllableAssetCheck, accountUseCase = accountUseCase, resourceManager = resourceManager, - assetIconProvider = assetIconProvider + assetIconProvider = assetIconProvider, + amountFormatter = amountFormatter ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index 879342e0d9..681f42af1b 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -29,6 +29,7 @@ import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSw import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_swap_api.domain.interactor.SwapAvailabilityInteractor +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import io.novafoundation.nova.feature_wallet_api.presentation.model.fullChainAssetId import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch @@ -44,7 +45,8 @@ class AssetSwapFlowViewModel( private val swapAvailabilityInteractor: SwapAvailabilityInteractor, private val swapFlowExecutor: SwapFlowExecutor, private val swapPayload: SwapFlowPayload, - private val assetIconProvider: AssetIconProvider + private val assetIconProvider: AssetIconProvider, + private val amountFormatter: AmountFormatter ) : AssetFlowViewModel( interactorFactory, router, @@ -53,7 +55,8 @@ class AssetSwapFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, - assetIconProvider + assetIconProvider, + amountFormatter ) { init { @@ -96,7 +99,7 @@ class AssetSwapFlowViewModel( override fun mapNetworkAssets(assets: Map>, currency: Currency): List { return assets.mapGroupedAssetsToUi( - resourceManager, + amountFormatter, assetIconProvider, currency, NetworkAssetGroup::groupTransferableBalanceFiat, @@ -106,7 +109,7 @@ class AssetSwapFlowViewModel( override fun mapTokensAssets(assets: Map>): List { return assets.map { (group, assets) -> - mapTokenAssetGroupToUi(resourceManager, assetIconProvider, group, assets = assets) { it.groupBalance.transferable } + mapTokenAssetGroupToUi(amountFormatter, assetIconProvider, group, assets = assets) { it.groupBalance.transferable } } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt index db28356024..3ec77a335d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt @@ -20,6 +20,7 @@ import io.novafoundation.nova.feature_assets.presentation.swap.asset.SwapFlowPay import io.novafoundation.nova.feature_assets.presentation.swap.executor.SwapFlowExecutorFactory import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_swap_api.domain.interactor.SwapAvailabilityInteractor +import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter @Module(includes = [ViewModelModule::class]) class AssetSwapFlowModule { @@ -43,7 +44,8 @@ class AssetSwapFlowModule { payload: SwapFlowPayload, executorFactory: SwapFlowExecutorFactory, swapAvailabilityInteractor: SwapAvailabilityInteractor, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + amountFormatter: AmountFormatter ): ViewModel { return AssetSwapFlowViewModel( interactorFactory = interactorFactory, @@ -56,7 +58,8 @@ class AssetSwapFlowModule { swapFlowExecutor = executorFactory.create(payload), swapPayload = payload, swapAvailabilityInteractor = swapAvailabilityInteractor, - assetIconProvider = assetIconProvider + assetIconProvider = assetIconProvider, + amountFormatter = amountFormatter ) } } diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt index 8db9800eb4..0999e2b8a4 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt @@ -9,23 +9,37 @@ import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.formatting.toAmountWithFraction import io.novafoundation.nova.feature_wallet_api.R -fun CharSequence.formatBalanceWithFraction(resourceManager: ResourceManager, @DimenRes floatAmountSize: Int): CharSequence { - val amountWithFraction = toAmountWithFraction() - - val textColor = resourceManager.getColor(R.color.text_secondary) - val colorSpan = ForegroundColorSpan(textColor) - val sizeSpan = AbsoluteSizeSpan(resourceManager.getDimensionPixelSize(floatAmountSize)) - - return with(amountWithFraction) { - val spannableBuilder = SpannableStringBuilder() - .append(amount) - if (fraction != null) { - spannableBuilder.append(separator + fraction) - val startIndex = amount.length - val endIndex = amount.length + separator.length + fraction!!.length - spannableBuilder.setSpan(colorSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) - spannableBuilder.setSpan(sizeSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) +interface AmountFormatter { + + fun formatBalanceWithFraction(amount: CharSequence, @DimenRes floatAmountSize: Int): CharSequence +} + +class RealAmountFormatter( + private val resourceManager: ResourceManager +) : AmountFormatter { + + override fun formatBalanceWithFraction(amount: CharSequence, @DimenRes floatAmountSize: Int): CharSequence { + val amountWithFraction = amount.toAmountWithFraction() + + val textColor = resourceManager.getColor(R.color.text_secondary) + val colorSpan = ForegroundColorSpan(textColor) + val sizeSpan = AbsoluteSizeSpan(resourceManager.getDimensionPixelSize(floatAmountSize)) + + return with(amountWithFraction) { + val spannableBuilder = SpannableStringBuilder() + .append(amount) + if (fraction != null) { + spannableBuilder.append(separator + fraction) + val startIndex = amount.length + val endIndex = amount.length + separator.length + fraction!!.length + spannableBuilder.setSpan(colorSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + spannableBuilder.setSpan(sizeSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } + spannableBuilder } - spannableBuilder } } + +fun CharSequence.formatBalanceWithFraction(formatter: AmountFormatter, @DimenRes floatAmountSize: Int): CharSequence { + return formatter.formatBalanceWithFraction(this, floatAmountSize) +} diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt index 526f7646db..38140a1b6f 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt @@ -1,7 +1,6 @@ package io.novafoundation.nova.feature_wallet_api.presentation.model import androidx.annotation.DimenRes -import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.formatting.format import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency import io.novafoundation.nova.feature_wallet_api.domain.model.Asset @@ -99,9 +98,9 @@ fun Asset.transferableAmountModel() = mapAmountToAmountModel(transferable, this) fun transferableAmountModelOf(asset: Asset) = mapAmountToAmountModel(asset.transferable, asset) -fun AmountModel.formatBalanceWithFraction(resourceManager: ResourceManager, @DimenRes floatAmountSize: Int): AmountModel { +fun AmountModel.formatBalanceWithFraction(amountFormatter: AmountFormatter, @DimenRes floatAmountSize: Int): AmountModel { return AmountModel( - token = token.formatBalanceWithFraction(resourceManager, floatAmountSize), + token = token.formatBalanceWithFraction(amountFormatter, floatAmountSize), fiat = fiat ) } From 7f24b647bd3fd99122365bbdd0610919bb70a58c Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 7 Nov 2024 10:53:25 +0100 Subject: [PATCH 61/78] Update navigation --- .../nova/app/root/navigation/Navigator.kt | 11 ++--- .../app/root/navigation/swap/SwapNavigator.kt | 4 +- .../main/res/navigation/main_nav_graph.xml | 6 +-- .../select_swap_token_nav_graph.xml | 33 +++++++++++++ .../res/navigation/start_swap_nav_graph.xml | 12 ++--- .../main/res/navigation/swap_flow_graph.xml | 47 ------------------- .../presentation/AssetsRouter.kt | 2 +- .../swap/executor/ReselectSwapFlowExecutor.kt | 2 +- 8 files changed, 49 insertions(+), 68 deletions(-) create mode 100644 app/src/main/res/navigation/select_swap_token_nav_graph.xml delete mode 100644 app/src/main/res/navigation/swap_flow_graph.xml diff --git a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt index a201808540..b31933209d 100644 --- a/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt +++ b/app/src/main/java/io/novafoundation/nova/app/root/navigation/Navigator.kt @@ -396,20 +396,15 @@ class Navigator( } override fun openSwapNetworks(payload: NetworkSwapFlowPayload) { - navController?.navigate(R.id.action_swapFlow_to_swapFlowNetwork, NetworkSwapFlowFragment.createPayload(payload)) + navController?.navigate(R.id.action_selectAssetSwapFlowFragment_to_swapFlowNetworkFragment, NetworkSwapFlowFragment.createPayload(payload)) } override fun openBuyNetworks(payload: NetworkFlowPayload) { navController?.navigate(R.id.action_buyFlow_to_buyFlowNetwork, NetworkFlowFragment.createPayload(payload)) } - override fun backFromSwapFlow() { - performNavigation( - cases = arrayOf( - R.id.swapFlowFragment to R.id.action_back_swapFlowFragment, - R.id.swapFlowNetworkFragment to R.id.action_back_swapFlowNetworkFragment - ) - ) + override fun returnToMainSwapScreen() { + navController?.navigate(R.id.action_return_to_swap_settings) } override fun openSwapFlow() { diff --git a/app/src/main/java/io/novafoundation/nova/app/root/navigation/swap/SwapNavigator.kt b/app/src/main/java/io/novafoundation/nova/app/root/navigation/swap/SwapNavigator.kt index a52457f9d9..ba72cd2dae 100644 --- a/app/src/main/java/io/novafoundation/nova/app/root/navigation/swap/SwapNavigator.kt +++ b/app/src/main/java/io/novafoundation/nova/app/root/navigation/swap/SwapNavigator.kt @@ -33,12 +33,12 @@ class SwapNavigator( override fun selectAssetIn(selectedAsset: AssetPayload?) { val payload = SwapFlowPayload.ReselectAssetIn(selectedAsset) - navigationHolder.navController?.navigate(R.id.action_swapMainSettingsFragment_to_swapFlow, AssetSwapFlowFragment.getBundle(payload)) + navigationHolder.navController?.navigate(R.id.action_swapSettingsFragment_to_select_swap_token_graph, AssetSwapFlowFragment.getBundle(payload)) } override fun selectAssetOut(selectedAsset: AssetPayload?) { val payload = SwapFlowPayload.ReselectAssetOut(selectedAsset) - navigationHolder.navController?.navigate(R.id.action_swapMainSettingsFragment_to_swapFlow, AssetSwapFlowFragment.getBundle(payload)) + navigationHolder.navController?.navigate(R.id.action_swapSettingsFragment_to_select_swap_token_graph, AssetSwapFlowFragment.getBundle(payload)) } override fun openSendCrossChain(destination: AssetPayload, recipientAddress: String?) { diff --git a/app/src/main/res/navigation/main_nav_graph.xml b/app/src/main/res/navigation/main_nav_graph.xml index 24c4169c17..d085d337b2 100644 --- a/app/src/main/res/navigation/main_nav_graph.xml +++ b/app/src/main/res/navigation/main_nav_graph.xml @@ -217,7 +217,7 @@ - + \ No newline at end of file diff --git a/app/src/main/res/navigation/select_swap_token_nav_graph.xml b/app/src/main/res/navigation/select_swap_token_nav_graph.xml new file mode 100644 index 0000000000..45123fda55 --- /dev/null +++ b/app/src/main/res/navigation/select_swap_token_nav_graph.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/start_swap_nav_graph.xml b/app/src/main/res/navigation/start_swap_nav_graph.xml index 9577fda503..9d9fdb5c4a 100644 --- a/app/src/main/res/navigation/start_swap_nav_graph.xml +++ b/app/src/main/res/navigation/start_swap_nav_graph.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/app/src/main/res/navigation/swap_flow_graph.xml b/app/src/main/res/navigation/swap_flow_graph.xml deleted file mode 100644 index 9b549cca9c..0000000000 --- a/app/src/main/res/navigation/swap_flow_graph.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt index d15ac530a5..8f079be64e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/AssetsRouter.kt @@ -84,5 +84,5 @@ interface AssetsRouter { fun openBuyNetworks(payload: NetworkFlowPayload) - fun backFromSwapFlow() + fun returnToMainSwapScreen() } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/ReselectSwapFlowExecutor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/ReselectSwapFlowExecutor.kt index 51176c8542..5b8d2854d3 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/ReselectSwapFlowExecutor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/executor/ReselectSwapFlowExecutor.kt @@ -22,6 +22,6 @@ class ReselectSwapFlowExecutor( SelectingDirection.OUT -> state.setAssetOut(chainAsset) } - assetsRouter.backFromSwapFlow() + assetsRouter.returnToMainSwapScreen() } } From e7bc413d87d8d4ce5b563a8123b39b196880be97 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Thu, 7 Nov 2024 12:27:39 +0100 Subject: [PATCH 62/78] Fixed naming and chain icon --- ...Service.kt => AssetsViewModeRepository.kt} | 0 .../nova/common/di/CommonApi.kt | 3 ++ .../nova/common/di/modules/CommonModule.kt | 8 +++++ .../interactor/AssetViewModeInteractor.kt | 30 +++++++++++++++++++ common/src/main/res/values/strings.xml | 3 ++ .../di/AssetsFeatureDependencies.kt | 3 ++ .../common/holders/TokenAssetViewHolder.kt | 4 +-- .../buy/flow/asset/AssetBuyFlowViewModel.kt | 7 +++-- .../buy/flow/asset/di/AssetBuyFlowModule.kt | 7 +++-- .../flow/asset/AssetFlowFragment.kt | 4 +++ .../flow/asset/AssetFlowViewModel.kt | 13 +++++++- .../flow/asset/AssetReceiveFlowViewModel.kt | 7 +++-- .../flow/asset/di/AssetReceiveFlowModule.kt | 7 +++-- .../send/flow/asset/AssetSendFlowViewModel.kt | 7 +++-- .../send/flow/asset/di/AssetSendFlowModule.kt | 7 +++-- .../swap/asset/AssetSwapFlowViewModel.kt | 7 +++-- .../swap/asset/di/AssetSwapFlowModule.kt | 7 +++-- .../res/layout/fragment_asset_flow_search.xml | 2 +- .../src/main/res/layout/fragment_receive.xml | 2 +- 19 files changed, 107 insertions(+), 21 deletions(-) rename common/src/main/java/io/novafoundation/nova/common/data/repository/{AssetsViewModeService.kt => AssetsViewModeRepository.kt} (100%) create mode 100644 common/src/main/java/io/novafoundation/nova/common/domain/interactor/AssetViewModeInteractor.kt diff --git a/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeService.kt b/common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt similarity index 100% rename from common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeService.kt rename to common/src/main/java/io/novafoundation/nova/common/data/repository/AssetsViewModeRepository.kt diff --git a/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt b/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt index f148d5d495..01b93537de 100644 --- a/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt +++ b/common/src/main/java/io/novafoundation/nova/common/di/CommonApi.kt @@ -22,6 +22,7 @@ import io.novafoundation.nova.common.data.secrets.v2.SecretStoreV2 import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.data.storage.encrypt.EncryptedPreferences import io.novafoundation.nova.common.di.modules.Caching +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor import io.novafoundation.nova.common.interfaces.ActivityIntentProvider import io.novafoundation.nova.common.interfaces.BuildTypeProvider import io.novafoundation.nova.common.interfaces.FileCache @@ -192,4 +193,6 @@ interface CommonApi { fun assetsIconModeService(): AssetsIconModeRepository fun assetIconProvider(): AssetIconProvider + + fun assetViewModeInteractor(): AssetViewModeInteractor } diff --git a/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt b/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt index 7e2440a0f7..bf958cbee2 100644 --- a/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt +++ b/common/src/main/java/io/novafoundation/nova/common/di/modules/CommonModule.kt @@ -35,6 +35,8 @@ import io.novafoundation.nova.common.data.storage.encrypt.EncryptedPreferences import io.novafoundation.nova.common.data.storage.encrypt.EncryptedPreferencesImpl import io.novafoundation.nova.common.data.storage.encrypt.EncryptionUtil import io.novafoundation.nova.common.di.scope.ApplicationScope +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor +import io.novafoundation.nova.common.domain.interactor.RealAssetViewModeInteractor import io.novafoundation.nova.common.interfaces.FileCache import io.novafoundation.nova.common.interfaces.FileProvider import io.novafoundation.nova.common.interfaces.InternalFileSystemCache @@ -359,6 +361,12 @@ class CommonModule { @ApplicationScope fun provideAssetsViewModeRepository(preferences: Preferences): AssetsViewModeRepository = RealAssetsViewModeRepository(preferences) + @Provides + @ApplicationScope + fun provideAssetViewModeInteractor(repository: AssetsViewModeRepository): AssetViewModeInteractor { + return RealAssetViewModeInteractor(repository) + } + @Provides @ApplicationScope fun provideAssetsIconModeRepository(preferences: Preferences): AssetsIconModeRepository = RealAssetsIconModeRepository(preferences) diff --git a/common/src/main/java/io/novafoundation/nova/common/domain/interactor/AssetViewModeInteractor.kt b/common/src/main/java/io/novafoundation/nova/common/domain/interactor/AssetViewModeInteractor.kt new file mode 100644 index 0000000000..f9a7d15fe3 --- /dev/null +++ b/common/src/main/java/io/novafoundation/nova/common/domain/interactor/AssetViewModeInteractor.kt @@ -0,0 +1,30 @@ +package io.novafoundation.nova.common.domain.interactor + +import io.novafoundation.nova.common.data.model.AssetViewMode +import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository +import kotlinx.coroutines.flow.Flow + +interface AssetViewModeInteractor { + + fun getAssetViewMode(): AssetViewMode + + fun assetsViewModeFlow(): Flow + + suspend fun setAssetsViewMode(assetsViewMode: AssetViewMode) +} + +class RealAssetViewModeInteractor( + private val assetsViewModeRepository: AssetsViewModeRepository +) : AssetViewModeInteractor { + override fun getAssetViewMode(): AssetViewMode { + return assetsViewModeRepository.getAssetViewMode() + } + + override fun assetsViewModeFlow(): Flow { + return assetsViewModeRepository.assetsViewModeFlow() + } + + override suspend fun setAssetsViewMode(assetsViewMode: AssetViewMode) { + assetsViewModeRepository.setAssetsViewMode(assetsViewMode) + } +} diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index 92b65c89e5..5edea2541d 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -1,6 +1,9 @@ + Search by token + + Copy Address Send only %1$s token and tokens in %2$s network to this address, or you might lose your funds token icons diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt index 0d2b1766ff..86d943ecbe 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/di/AssetsFeatureDependencies.kt @@ -15,6 +15,7 @@ import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository import io.novafoundation.nova.common.data.storage.Preferences import io.novafoundation.nova.common.data.storage.encrypt.EncryptedPreferences +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor import io.novafoundation.nova.common.interfaces.FileProvider import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin import io.novafoundation.nova.common.mixin.hints.ResourcesHintsMixinFactory @@ -261,4 +262,6 @@ interface AssetsFeatureDependencies { fun assetsIconModeRepository(): AssetsIconModeRepository fun nftRepository(): NftRepository + + fun assetViewModeInteractor(): AssetViewModeInteractor } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt index fff22ec99b..ec14307d77 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt @@ -6,7 +6,7 @@ import io.novafoundation.nova.common.list.GroupedListHolder import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableChildViewHolder import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem -import io.novafoundation.nova.feature_account_api.presenatation.chain.loadTokenIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.loadChainIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel @@ -29,7 +29,7 @@ class TokenAssetViewHolder( val asset = tokenAsset.asset itemTokenAssetImage.setIcon(tokenAsset.assetIcon, imageLoader) - itemTokenAssetChainIcon.loadTokenIcon(tokenAsset.chain.icon, imageLoader) + itemTokenAssetChainIcon.loadChainIcon(tokenAsset.chain.icon, imageLoader) itemTokenAssetChainName.text = tokenAsset.chain.name bindTotal(asset) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt index b035823fc2..edc928a128 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.buy.flow.asset +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -25,7 +26,8 @@ class AssetBuyFlowViewModel( accountUseCase: SelectedAccountUseCase, buyMixinFactory: BuyMixin.Factory, resourceManager: ResourceManager, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + assetViewModeInteractor: AssetViewModeInteractor ) : AssetFlowViewModel( interactorFactory, router, @@ -34,7 +36,8 @@ class AssetBuyFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, - assetIconProvider + assetIconProvider, + assetViewModeInteractor ) { val buyMixin = buyMixinFactory.create(scope = this) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt index fe132b056e..a08c33be7d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/di/AssetBuyFlowModule.kt @@ -8,6 +8,7 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -39,7 +40,8 @@ class AssetBuyFlowModule { accountUseCase: SelectedAccountUseCase, buyMixinFactory: BuyMixin.Factory, resourceManager: ResourceManager, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + assetViewModeInteractor: AssetViewModeInteractor ): ViewModel { return AssetBuyFlowViewModel( interactorFactory = interactorFactory, @@ -50,7 +52,8 @@ class AssetBuyFlowModule { accountUseCase = accountUseCase, buyMixinFactory = buyMixinFactory, resourceManager = resourceManager, - assetIconProvider = assetIconProvider + assetIconProvider = assetIconProvider, + assetViewModeInteractor = assetViewModeInteractor ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt index 42c80a8c9f..61c5ce5b32 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt @@ -86,6 +86,10 @@ abstract class AssetFlowFragment : override fun subscribe(viewModel: T) { assetFlowToolbar.searchField.content.bindTo(viewModel.query, lifecycleScope) + viewModel.searchHint.observe { + assetFlowToolbar.searchField.setHint(it) + } + viewModel.searchResults.observe { assets -> assetFlowList.setVisible(assets.isNotEmpty()) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index e60d393abd..1299ba1039 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -1,6 +1,8 @@ package io.novafoundation.nova.feature_assets.presentation.flow.asset import io.novafoundation.nova.common.base.BaseViewModel +import io.novafoundation.nova.common.data.model.AssetViewMode +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.flowOfAll @@ -41,7 +43,8 @@ abstract class AssetFlowViewModel( protected val accountUseCase: SelectedAccountUseCase, externalBalancesInteractor: ExternalBalancesInteractor, protected val resourceManager: ResourceManager, - private val assetIconProvider: AssetIconProvider + private val assetIconProvider: AssetIconProvider, + private val assetViewModeInteractor: AssetViewModeInteractor ) : BaseViewModel() { protected val interactor = interactorFactory.createByAssetViewMode() @@ -59,6 +62,14 @@ abstract class AssetFlowViewModel( private val searchAssetsFlow = flowOfAll { searchAssetsFlow() } // lazy use searchAssetsFlow to let subclasses initialize self .shareInBackground(SharingStarted.Lazily) + val searchHint = assetViewModeInteractor.assetsViewModeFlow() + .map { + when (it) { + AssetViewMode.NETWORKS -> resourceManager.getString(R.string.assets_search_hint) + AssetViewMode.TOKENS -> resourceManager.getString(R.string.assets_search_token_hint) + } + } + val searchResults = combine( searchAssetsFlow, selectedCurrency, diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt index 41242fac2d..7126312b50 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.receive.flow.asset +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -24,7 +25,8 @@ class AssetReceiveFlowViewModel( controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + assetViewModeInteractor: AssetViewModeInteractor ) : AssetFlowViewModel( interactorFactory, router, @@ -33,7 +35,8 @@ class AssetReceiveFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, - assetIconProvider + assetIconProvider, + assetViewModeInteractor ) { override fun searchAssetsFlow(): Flow { return interactor.searchReceiveAssetsFlow(query, externalBalancesFlow) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt index aab728526b..43da8e5a1f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/di/AssetReceiveFlowModule.kt @@ -8,6 +8,7 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -37,7 +38,8 @@ class AssetReceiveFlowModule { controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + assetViewModeInteractor: AssetViewModeInteractor ): ViewModel { return AssetReceiveFlowViewModel( interactorFactory = interactorFactory, @@ -47,7 +49,8 @@ class AssetReceiveFlowModule { controllableAssetCheck = controllableAssetCheck, accountUseCase = accountUseCase, resourceManager = resourceManager, - assetIconProvider = assetIconProvider + assetIconProvider = assetIconProvider, + assetViewModeInteractor = assetViewModeInteractor ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt index 66542798d2..378bc4010e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_assets.presentation.send.flow.asset +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.view.PlaceholderModel @@ -36,7 +37,8 @@ class AssetSendFlowViewModel( controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, - private val assetIconProvider: AssetIconProvider + private val assetIconProvider: AssetIconProvider, + assetViewModeInteractor: AssetViewModeInteractor ) : AssetFlowViewModel( interactorFactory, router, @@ -45,7 +47,8 @@ class AssetSendFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, - assetIconProvider + assetIconProvider, + assetViewModeInteractor ) { override fun searchAssetsFlow(): Flow { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt index 45f08cb0c9..e778a76c1c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/di/AssetSendFlowModule.kt @@ -8,6 +8,7 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -37,7 +38,8 @@ class AssetSendFlowModule { controllableAssetCheck: ControllableAssetCheckMixin, accountUseCase: SelectedAccountUseCase, resourceManager: ResourceManager, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + assetViewModeInteractor: AssetViewModeInteractor ): ViewModel { return AssetSendFlowViewModel( interactorFactory = interactorFactory, @@ -47,7 +49,8 @@ class AssetSendFlowModule { controllableAssetCheck = controllableAssetCheck, accountUseCase = accountUseCase, resourceManager = resourceManager, - assetIconProvider = assetIconProvider + assetIconProvider = assetIconProvider, + assetViewModeInteractor = assetViewModeInteractor ) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index e777c1f70a..c1c201344d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.feature_assets.presentation.swap.asset import androidx.annotation.StringRes import androidx.lifecycle.viewModelScope +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.utils.launchUnit @@ -44,7 +45,8 @@ class AssetSwapFlowViewModel( private val swapAvailabilityInteractor: SwapAvailabilityInteractor, private val swapFlowExecutor: SwapFlowExecutor, private val swapPayload: SwapFlowPayload, - private val assetIconProvider: AssetIconProvider + private val assetIconProvider: AssetIconProvider, + assetViewModeInteractor: AssetViewModeInteractor ) : AssetFlowViewModel( interactorFactory, router, @@ -53,7 +55,8 @@ class AssetSwapFlowViewModel( accountUseCase, externalBalancesInteractor, resourceManager, - assetIconProvider + assetIconProvider, + assetViewModeInteractor ) { init { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt index db28356024..ba443f5c54 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/di/AssetSwapFlowModule.kt @@ -8,6 +8,7 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey import io.novafoundation.nova.common.di.viewmodel.ViewModelModule +import io.novafoundation.nova.common.domain.interactor.AssetViewModeInteractor import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase @@ -43,7 +44,8 @@ class AssetSwapFlowModule { payload: SwapFlowPayload, executorFactory: SwapFlowExecutorFactory, swapAvailabilityInteractor: SwapAvailabilityInteractor, - assetIconProvider: AssetIconProvider + assetIconProvider: AssetIconProvider, + assetViewModeInteractor: AssetViewModeInteractor ): ViewModel { return AssetSwapFlowViewModel( interactorFactory = interactorFactory, @@ -56,7 +58,8 @@ class AssetSwapFlowModule { swapFlowExecutor = executorFactory.create(payload), swapPayload = payload, swapAvailabilityInteractor = swapAvailabilityInteractor, - assetIconProvider = assetIconProvider + assetIconProvider = assetIconProvider, + assetViewModeInteractor = assetViewModeInteractor ) } } diff --git a/feature-assets/src/main/res/layout/fragment_asset_flow_search.xml b/feature-assets/src/main/res/layout/fragment_asset_flow_search.xml index 86bf06c615..44ce8a3cd2 100644 --- a/feature-assets/src/main/res/layout/fragment_asset_flow_search.xml +++ b/feature-assets/src/main/res/layout/fragment_asset_flow_search.xml @@ -12,7 +12,7 @@ android:id="@+id/assetFlowToolbar" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/assets_search_hint" + tools:hint="@string/assets_search_hint" tools:titleText="@string/wallet_asset_send" /> android:layout_width="wrap_content" android:layout_height="40dp" android:layout_gravity="center_horizontal" - android:text="@string/common_copy_address" + android:text="@string/receive_screen_copy_address" android:textAppearance="@style/TextAppearance.NovaFoundation.Regular.Caption1" android:textColor="@color/button_text_accent" app:icon="@drawable/ic_copy_outline" From d5794d79d2b5fdb6aed8e0533f4fb31db5f9647c Mon Sep 17 00:00:00 2001 From: leohar Date: Thu, 7 Nov 2024 16:58:46 +0000 Subject: [PATCH 63/78] add portfolio localisation --- common/src/main/res/values-es/strings.xml | 13 +++++++++++++ common/src/main/res/values-fr-rFR/strings.xml | 13 +++++++++++++ common/src/main/res/values-in/strings.xml | 13 +++++++++++++ common/src/main/res/values-it/strings.xml | 13 +++++++++++++ common/src/main/res/values-ja/strings.xml | 13 +++++++++++++ common/src/main/res/values-ko/strings.xml | 13 +++++++++++++ common/src/main/res/values-pl/strings.xml | 13 +++++++++++++ common/src/main/res/values-pt/strings.xml | 13 +++++++++++++ common/src/main/res/values-ru/strings.xml | 13 +++++++++++++ common/src/main/res/values-tr/strings.xml | 13 +++++++++++++ common/src/main/res/values-vi/strings.xml | 13 +++++++++++++ common/src/main/res/values-zh-rCN/strings.xml | 13 +++++++++++++ 12 files changed, 156 insertions(+) diff --git a/common/src/main/res/values-es/strings.xml b/common/src/main/res/values-es/strings.xml index 9c7ef274da..2d5c85e18f 100644 --- a/common/src/main/res/values-es/strings.xml +++ b/common/src/main/res/values-es/strings.xml @@ -173,6 +173,10 @@ Has alcanzado el límite de %s proxies añadidos en %s. Elimina proxies para añadir nuevos. Se ha alcanzado el número máximo de proxies Las redes personalizadas agregadas\naquí aparecerán + Coloreado + Apariencia + iconos de token + Blanco La dirección de contrato ingresada ya está presente en Nova como un token %s. La dirección de contrato ingresada ya está presente en Nova como un token %s. ¿Estás seguro de que quieres modificarlo? Este token ya existe @@ -185,6 +189,8 @@ Ingrese la dirección del contrato Ingrese los decimales Ingrese el símbolo + Redes + Tokens Agregar token Dirección del contrato Decimales @@ -207,6 +213,7 @@ Ledger no admite este token Buscar por red o token No se encontraron redes o tokens con\n el nombre ingresado + Buscar por token Sus carteras No tiene tokens para enviar.\nCompre o reciba tokens en su\ncuenta. Token para pagar @@ -235,6 +242,7 @@ Respaldar Autenticación biométrica ¡Compra iniciada! Por favor, espere hasta 60 minutos. Puede seguir el estado en el correo electrónico. + Seleccionar red para comprar %s Para continuar la compra será redirigido desde la aplicación Nova Wallet a %s ¿Continuar en el navegador? Equilibrar nodos automáticamente @@ -968,6 +976,8 @@ Al habilitar las notificaciones push, acepta nuestros %s y %s Intente de nuevo más tarde accediendo a los ajustes de notificación desde la pestaña de Configuración ¡No te pierdas de nada! + Seleccionar red para recibir %s + Copiar dirección Pega el json o sube un archivo… Subir archivo Restaurar JSON @@ -1125,6 +1135,7 @@ Seleccione pistas para %d de %d Dirección o w3n + Seleccionar red para enviar %s El destinatario es una cuenta del sistema. No está controlado por ninguna empresa o individuo.\n¿Estás seguro de que aún quieres realizar esta transferencia? Los tokens se perderán Otorgar autoridad a @@ -1534,6 +1545,7 @@ Ingresa otro monto Para pagar la comisión de red con %s, Nova intercambiará automáticamente %s por %s para mantener el balance mínimo de %s en tu cuenta. Una comisión de red cobrada por la cadena de bloques para procesar y validar cualquier transacción. Puede variar dependiendo de las condiciones de la red o la velocidad de la transacción. + Seleccionar red para intercambiar %s El fondo no tiene suficiente liquidez para intercambiar La diferencia de precio se refiere a la diferencia en el precio entre dos activos diferentes. Al realizar un intercambio en cripto, la diferencia de precio es generalmente la diferencia entre el precio del activo por el que estás intercambiando y el precio del activo con el que estás intercambiando. Diferencia de precio @@ -1626,6 +1638,7 @@ Comprar con Recibir Recibir %s + Enviar solo el token %1$s y tokens en la red %2$s a esta dirección, o podrías perder tus fondos Enviar Intercambiar Activos diff --git a/common/src/main/res/values-fr-rFR/strings.xml b/common/src/main/res/values-fr-rFR/strings.xml index df5fbce85c..1093eadfca 100644 --- a/common/src/main/res/values-fr-rFR/strings.xml +++ b/common/src/main/res/values-fr-rFR/strings.xml @@ -173,6 +173,10 @@ Vous avez atteint la limite de %s proxies ajoutés dans %s. Supprimez des proxies pour en ajouter de nouveaux. Le nombre maximum de proxies a été atteint Les réseaux personnalisés ajoutés\napparaîtront ici + Coloré + Apparence + icônes des tokens + Blanc L\'adresse du contrat saisie est présente dans Nova sous la forme d\'un jeton %s. L\'adresse du contrat saisie est présente dans Nova comme un token %s. Êtes-vous sûr de vouloir le modifier ? Ce jeton existe déjà @@ -185,6 +189,8 @@ Entrez l\'adresse du contrat Entrez les décimales Entrez le symbole + Réseaux + Tokens Ajouter un jeton Adresse du contrat Décimales @@ -207,6 +213,7 @@ Ledger ne prend pas en charge cet actif Recherche par réseau ou actif Aucun réseau ou jeton avec\nnom saisi n\'a été trouvé + Rechercher par token Vos portefeuilles Vous n\'avez pas de tokens à envoyer.\nAchetez ou recevez des tokens sur votre\ncompte. Token à payer @@ -235,6 +242,7 @@ Sauvegarde Auth biométrique L\'achat est lancé ! Veuillez patienter jusqu\'à 60 minutes. Vous pouvez suivre l\'état d\'avancement sur l\'e-mail. + Sélectionner le réseau pour acheter %s Pour poursuivre l\'achat, vous serez redirigé de l\'application Nova Wallet vers %s Continuer dans le navigateur? Équilibrage automatique des nœuds @@ -968,6 +976,8 @@ En activant les notifications push, vous acceptez nos %s et %s Veuillez réessayer plus tard en accédant aux paramètres de notification depuis l\'onglet Paramètres Ne manquez rien ! + Sélectionner le réseau pour recevoir %s + Copier l\'adresse Collez le fichier JSON ou téléchargez le fichier... Télécharger le fichier Restaurer JSON @@ -1125,6 +1135,7 @@ Sélectionner des pistes pour %d sur %d Adresse ou w3n + Sélectionner le réseau pour envoyer %s Le destinataire est un compte système. Il n\'est contrôlé par aucune entreprise ou individu.\nÊtes-vous sûr de vouloir effectuer ce transfert ? Les tokens seront perdus Donner l\'autorité à @@ -1534,6 +1545,7 @@ Entrez un autre montant Pour payer les frais de réseau avec %s, Nova échangera automatiquement %s contre %s pour maintenir le solde minimum de %s sur votre compte. Des frais de réseau facturés par la blockchain pour traiter et valider toutes les transactions. Ils peuvent varier en fonction des conditions du réseau ou de la rapidité de la transaction. + Sélectionner le réseau pour échanger %s Le pool n\'a pas assez de liquidité pour échanger La différence de prix fait référence à la différence de prix entre deux actifs différents. Lors de l\'échange en crypto, la différence de prix est généralement la différence entre le prix de l\'actif que vous échangez et le prix de l\'actif avec lequel vous échangez. Différence de prix @@ -1626,6 +1638,7 @@ Acheter avec Recevoir Recevoir %s + Envoyez uniquement le token %1$s et les tokens dans le réseau %2$s à cette adresse, ou vous pourriez perdre vos fonds Envoyer Échanger Actifs diff --git a/common/src/main/res/values-in/strings.xml b/common/src/main/res/values-in/strings.xml index 2c83b7e843..e66f9d5448 100644 --- a/common/src/main/res/values-in/strings.xml +++ b/common/src/main/res/values-in/strings.xml @@ -173,6 +173,10 @@ Anda telah mencapai batas %s proxy yang ditambahkan dalam %s. Hapus proxy untuk menambahkan yang baru. Jumlah maksimum proxy telah tercapai Jaringan kustom yang ditambahkan\nakan muncul di sini + Berwarna + Penampilan + ikon token + Putih Alamat kontrak yang dimasukkan ada dalam Nova sebagai token %s. Alamat kontrak yang dimasukkan ada dalam Nova sebagai token %s. Apakah Anda yakin ingin memodifikasinya? Token ini sudah ada @@ -185,6 +189,8 @@ Masukkan alamat kontrak Masukkan desimal Masukkan simbol + Jaringan + Token Tambahkan token Alamat kontrak Desimal @@ -207,6 +213,7 @@ Ledger tidak mendukung token ini Cari berdasarkan jaringan atau token Tidak ada jaringan atau token dengan nama yang dimasukkan ditemukan + Cari berdasarkan token Dompet Anda Anda tidak memiliki token untuk dikirim. Beli atau Terima token ke akun Anda. Token untuk membayar @@ -235,6 +242,7 @@ Cadangan Otentikasi Biometrik Pembelian dimulai! Harap tunggu hingga 60 menit. Anda dapat melacak statusnya melalui email. + Pilih jaringan untuk membeli %s Untuk melanjutkan pembelian, Anda akan diarahkan dari aplikasi Nova Wallet ke %s Lanjut di browser? Node saldo otomatis @@ -961,6 +969,8 @@ Dengan mengaktifkan pemberitahuan push, Anda menyetujui %s dan %s kami Harap coba lagi nanti dengan mengakses pengaturan pemberitahuan dari tab Pengaturan Jangan lewatkan hal apa pun! + Pilih jaringan untuk menerima %s + Salin Alamat Tempelkan json atau unggah file... Unggah file Pulihkan JSON @@ -1117,6 +1127,7 @@ Select tracks for %d of %d Address or w3n + Pilih jaringan untuk mengirim %s Recipient is a system account. It is not controlled by any company or individual.\nAre you sure you still want to perform this transfer? Tokens will be lost Give authority to @@ -1524,6 +1535,7 @@ Masukkan jumlah lain Untuk membayar biaya jaringan dengan %s, Nova secara otomatis akan menukar %s dengan %s untuk mempertahankan saldo minimum %s akun Anda. Biaya jaringan yang dibebankan oleh blockchain untuk memproses dan memvalidasi transaksi. Bisa bervariasi tergantung pada kondisi jaringan atau kecepatan transaksi. + Pilih jaringan untuk menukar %s Pool tidak memiliki likuiditas yang cukup untuk swap Perbedaan harga merujuk pada perbedaan harga antara dua aset yang berbeda. Ketika melakukan swap dalam kripto, perbedaan harga biasanya adalah perbedaan antara harga aset yang Anda tukarkan dengan harga aset yang Anda tukar. Perbedaan harga @@ -1616,6 +1628,7 @@ Beli dengan Terima Terima %s + Hanya kirim token %1$s dan token di jaringan %2$s ke alamat ini, atau Anda bisa kehilangan dana Anda Kirim Tukar Aset diff --git a/common/src/main/res/values-it/strings.xml b/common/src/main/res/values-it/strings.xml index df030d8362..eda74cbb6b 100644 --- a/common/src/main/res/values-it/strings.xml +++ b/common/src/main/res/values-it/strings.xml @@ -173,6 +173,10 @@ Hai raggiunto il limite di %s proxy aggiunti in %s. Rimuovi i proxy per aggiungerne di nuovi Limite massimo di proxy raggiunto Le reti personalizzate aggiunte\nappariranno qui + Colorato + Aspetto + icone dei token + Bianco L\'indirizzo del contratto inserito è presente in Nova come token %s. L\'indirizzo del contratto inserito è presente in Nova come token %s. Sei sicuro di volerlo modificare? Questo token esiste già @@ -185,6 +189,8 @@ Inserisci l\'indirizzo del contratto Inserisci i decimali Inserisci il simbolo + Reti + Token Aggiungi token Indirizzo del contratto Decimali @@ -207,6 +213,7 @@ Ledger non supporta questo token Cerca per rete o token Nessuna rete o token con il nome inserito è stata trovata + Cerca per token I tuoi portafogli Non hai token da inviare. \nCompra o ricevi token sul tuo \nconto. Token da pagare @@ -235,6 +242,7 @@ Backup Autenticazione biometrica Acquisto iniziato! Attendi fino a 60 minuti. Puoi controllare lo stato sulla email. + Seleziona la rete per l\'acquisto di %s Per continuare l\'acquisto sarai reindirizzato dall\'app Nova Wallet a %s Continuare nel browser? Bilanciamento automatico dei nodi @@ -968,6 +976,8 @@ Abilitando le notifiche push, accetti i nostri %s e %s Si prega di riprovare più tardi accedendo alle impostazioni delle notifiche dalla scheda Impostazioni Non perdere nulla! + Seleziona la rete per ricevere %s + Copia indirizzo Incolla json o carica il file... Carica file Ripristina JSON per il recupero @@ -1125,6 +1135,7 @@ Seleziona brani per %d di %d Indirizzo o w3n + Seleziona la rete per inviare %s Il destinatario è un conto di sistema. Non è controllato da alcuna azienda o individuo.\nSei sicuro di voler comunque effettuare questo trasferimento? I token verranno persi Conferire autorità a @@ -1534,6 +1545,7 @@ Inserisci un altro importo Per pagare la tariffa di rete con %s, Nova effettuerà automaticamente lo scambio di %s per %s per mantenere il saldo minimo del tuo account di %s. Una tariffa di rete addebitata dal blockchain per elaborare e convalidare qualsiasi transazione. Può variare a seconda delle condizioni di rete o della velocità delle transazioni. + Seleziona la rete per scambiare %s Il pool non ha abbastanza liquidità per lo scambio La differenza di prezzo si riferisce alla differenza di prezzo tra due diversi asset. Quando si effettua uno scambio in criptovaluta, la differenza di prezzo è di solito la differenza tra il prezzo dell\'asset che stai scambiando e il prezzo dell\'asset con cui stai scambiando. Differenza di prezzo @@ -1626,6 +1638,7 @@ Acquista con Ricevi Ricevi %s + Invia solo token %1$s e token nella rete %2$s a questo indirizzo, altrimenti potresti perdere i tuoi fondi Invia Scambia Asset diff --git a/common/src/main/res/values-ja/strings.xml b/common/src/main/res/values-ja/strings.xml index afb5a07e86..cf8ebfb504 100644 --- a/common/src/main/res/values-ja/strings.xml +++ b/common/src/main/res/values-ja/strings.xml @@ -173,6 +173,10 @@ %sで追加できるプロキシの上限に達しました。新しいものを追加するためには既存のプロキシを削除してください。 プロキシの最大数に達しました 追加されたカスタムネットワーク\nここに表示されます + カラー + 外観 + トークンアイコン + ホワイト 入力されたコントラクトアドレスは%sトークンとしてNovaに存在します。 入力されたコントラクトアドレスは%sトークンとしてNovaに存在します。本当にそれを変更しますか? このトークンはすでに存在します @@ -185,6 +189,8 @@ コントラクトアドレスを入力 小数を入力 シンボルを入力 + ネットワーク + トークン トークンを追加 コントラクトアドレス 小数 @@ -207,6 +213,7 @@ Ledgerはこのトークンをサポートしていません ネットワークまたはトークンで検索 入力した名前のネットワークやトークンが見つかりませんでした + トークンで検索 あなたのウォレット 送信するトークンがありません。\nトークンを購入または受け取ってください\nアカウントに。 支払い用トークン @@ -235,6 +242,7 @@ バックアップ 生体認証 購入が開始されました! 最大60分お待ちください。メールでステータスを追跡できます。 + 購入するネットワークを選択 %s 購入を続行するために、Nova Walletアプリから%sにリダイレクトされます。 ブラウザで続行しますか? 自動バランスノード @@ -961,6 +969,8 @@ プッシュ通知を有効にすることで、%sと%sに同意したことになります 設定タブから通知設定にアクセスして、後でもう一度お試しください お見逃しなく! + 受信するネットワークを選択 %s + 住所をコピー jsonを貼り付けるかファイルをアップロード... ファイルをアップロード JSONを復元 @@ -1117,6 +1127,7 @@ トラックを選択 %d / %d アドレスまたはw3n + 送信するネットワークを選択 %s 受信者はシステムアカウントです。どの会社や個人にも管理されていません。\nそれでもこの転送を実行してもよろしいですか? トークンが失われます 権限を与える @@ -1524,6 +1535,7 @@ 別の金額を入力 ネットワーク手数料を %s で支払うため、Novaは %s を %s に自動的にスワップして、アカウントの最低 %s 残高を維持します。 ブロックチェーンによって取引や検証を処理するためのネットワーク手数料。ネットワークの状況や取引速度によって異なる場合があります。 + スワップするネットワークを選択 %s プールにスワップするための十分な流動性がありません 価格差とは、二つの異なる資産間の価格差を指します。暗号通貨のスワップを行う際、価格差は通常、交換する資産の価格と交換される資産の価格の違いを意味します。 価格差 @@ -1616,6 +1628,7 @@ で購入 受け取る 受け取る %s + 送信するのは%1$sトークンと%2$sネットワークのトークンのみ可能です、それ以外の場合、資金を失う可能性があります 送信 スワップ 資産 diff --git a/common/src/main/res/values-ko/strings.xml b/common/src/main/res/values-ko/strings.xml index 4142aa26be..7334561d41 100644 --- a/common/src/main/res/values-ko/strings.xml +++ b/common/src/main/res/values-ko/strings.xml @@ -173,6 +173,10 @@ %s에서 추가된 프록시 수의 한도에 도달했습니다. 새로운 프록시를 추가하려면 기존 프록시를 제거하세요. 최대 프록시 수에 도달했습니다 추가된 사용자 정의 네트워크는 여기에 나타납니다 + 컬러 + 외관 + 토큰 아이콘 + 화이트 입력된 계약 주소는 Nova에서 %s 토큰으로 이미 존재합니다. 입력된 계약 주소는 Nova에서 %s 토큰으로 존재합니다. 수정하시겠습니까? 이 토큰은 이미 존재합니다 @@ -185,6 +189,8 @@ 계약 주소 입력 소수 자릿수 입력 심볼 입력 + 네트워크 + 토큰 토큰 추가 계약 주소 소수 자릿수 @@ -207,6 +213,7 @@ Ledger에서 이 토큰을 지원하지 않습니다. 네트워크 또는 토큰으로 검색 입력한 이름과 일치하는 네트워크 또는 토큰이 없습니다. + 토큰으로 검색 당신의 지갑 보낼 토큰이 없습니다.\n계정에 토큰을 구매하거나 수신하십시오. 지불할 토큰 @@ -235,6 +242,7 @@ 백업 생체 인증 구매가 시작되었습니다! 최대 60분까지 기다려주세요. 이메일에서 상태를 추적할 수 있습니다. + %s 구매를 위한 네트워크 선택 구매를 계속하려면 Nova Wallet 앱에서 %s로 리디렉션됩니다. 브라우저에서 계속할까요? 자동 균형 노드 @@ -961,6 +969,8 @@ 푸시 알림을 활성화함으로써 귀하는 우리의 %s 및 %s에 동의하게 됩니다 설정 탭에서 알림 설정에 접근하여 나중에 다시 시도해주세요 중요한 것을 놓치지 마세요! + %s 수신을 위한 네트워크 선택 + 주소 복사 json을 붙여넣거나 파일을 업로드하세요... 파일 업로드 JSON 복원 @@ -1117,6 +1127,7 @@ 트랙 선택 %d 중 %d 주소 또는 w3n + %s 전송을 위한 네트워크 선택 수신자가 시스템 계정입니다. 이 계정은 어떤 회사나 개인에 의해 제어되지 않습니다.\n여전히 이 전송을 수행하시겠습니까? 토큰이 소실됩니다 권한 부여 @@ -1524,6 +1535,7 @@ 다른 금액 입력 %s로 네트워크 수수료를 지불하기 위해, Nova는 계정의 최소 %s 잔액을 유지하기 위해 자동으로 %s를 %s로 교환합니다. 블록체인이 모든 거래를 처리하고 검증하기 위해 부과하는 네트워크 수수료입니다. 네트워크 상태나 거래 속도에 따라 다를 수 있습니다. + %s 교환을 위한 네트워크 선택 풀에 교환할 수 있는 유동성이 충분하지 않습니다 가격 차이는 두 자산 간의 가격 차이를 나타냅니다. 암호화폐 교환 시, 가격 차이는 일반적으로 교환하는 자산의 가격과 교환받는 자산의 가격 간의 차이를 의미합니다. 가격 차이 @@ -1616,6 +1628,7 @@ 구매 방법 받기 %s 수령 + 이 주소로 %1$s 토큰과 %2$s 네트워크에서의 토큰만 보내세요, 그렇지 않으면 자금을 잃을 수 있습니다. 보내기 스왑 자산 diff --git a/common/src/main/res/values-pl/strings.xml b/common/src/main/res/values-pl/strings.xml index 641ea2cf6e..4d9c03490d 100644 --- a/common/src/main/res/values-pl/strings.xml +++ b/common/src/main/res/values-pl/strings.xml @@ -173,6 +173,10 @@ Osiągnąłeś limit %s dodanych proxy w %s. Usuń proxy, aby dodać nowe. Osiągnięto maksymalną liczbę proxy Dodane niestandardowe sieci\npojawią się tutaj + Kolorowe + Wygląd + ikony tokenów + Białe Wprowadzony adres kontraktu jest obecny w Nova jako token %s. Wprowadzony adres kontraktu jest obecny w Nova jako token %s. Czy na pewno chcesz go zmodyfikować? Ten token już istnieje @@ -185,6 +189,8 @@ Wprowadź adres kontraktu Wprowadź liczbę miejsc dziesiętnych Wprowadź symbol + Sieci + Tokeny Dodaj token Adres kontraktu Liczba miejsc dziesiętnych @@ -207,6 +213,7 @@ Ledger nie obsługuje tego tokena Wyszukaj według sieci lub tokena Nie znaleziono sieci ani tokenów z\npodaną nazwą + Wyszukaj według tokena Twoje portfele Nie masz tokenów do wysłania.\nKup lub odbierz tokeny na swoje\nkonto. Token do zapłaty @@ -235,6 +242,7 @@ Kopia zapasowa Autoryzacja biometryczna Zakup zainicjowany! Proszę czekać do 60 minut. Możesz śledzić status na e-mail. + Wybierz sieć do kupna %s Aby kontynuować zakup, zostaniesz przekierowany z aplikacji Nova Wallet na %s Kontynuować w przeglądarce? Automatyczne równoważenie węzłów @@ -982,6 +990,8 @@ Włączając powiadomienia push, zgadzasz się na nasze %s i %s Spróbuj ponownie później, otwierając ustawienia powiadomień w zakładce Ustawienia Nie przegap niczego! + Wybierz sieć do otrzymania %s + Skopiuj adres Wklej json lub załaduj plik… Załaduj plik Przywróć JSON @@ -1141,6 +1151,7 @@ Wybierz trasy dla %d z %d Adres lub w3n + Wybierz sieć do wysyłki %s Odbiorca jest kontem systemowym. Nie jest kontrolowany przez żadną firmę ani osobę prywatną.\nCzy na pewno chcesz wykonać ten transfer? Tokeny zostaną utracone Nadaj uprawnienia @@ -1554,6 +1565,7 @@ Wprowadź inną kwotę Aby zapłacić opłatę sieciową za pomocą %s, Nova automatycznie zamieni %s na %s, aby utrzymać minimalne saldo %s na twoim koncie. Opłaty sieciowe pobierane przez blockchain za przetwarzanie i walidację dowolnych transakcji. Mogą się różnić w zależności od warunków sieci lub szybkości transakcji. + Wybierz sieć do zamiany %s W puli brakuje płynności do wymiany Różnica cenowa odnosi się do różnicy w cenie pomiędzy dwoma różnymi aktywami. Podczas wymiany w kryptowalutach, różnica cenowa zazwyczaj oznacza różnicę między ceną aktywa, którą otrzymujesz, a ceną aktywa, którą płacisz. Różnica cen @@ -1646,6 +1658,7 @@ Kup za Otrzymaj Otrzymaj %s + Wysyłaj tylko token %1$s i tokeny w sieci %2$s na ten adres, w przeciwnym razie możesz stracić swoje środki Wyślij Wymiana Aktywa diff --git a/common/src/main/res/values-pt/strings.xml b/common/src/main/res/values-pt/strings.xml index f42fb5c89f..e86459e34e 100644 --- a/common/src/main/res/values-pt/strings.xml +++ b/common/src/main/res/values-pt/strings.xml @@ -173,6 +173,10 @@ Você alcançou o limite de %s proxies adicionados em %s. Remova proxies para adicionar novos. Número máximo de proxies foi alcançado Redes personalizadas adicionadas\naparecerão aqui + Colorido + Aparência + ícones de token + Branco O endereço do contrato inserido já está presente na Nova como um token %s. O endereço do contrato inserido já está presente na Nova como um token %s. Tem certeza de que deseja modificá-lo? Este token já existe @@ -185,6 +189,8 @@ Insira o endereço do contrato Insira os decimais Insira o símbolo + Redes + Tokens Adicionar token Endereço do contrato Decimais @@ -207,6 +213,7 @@ Ledger não suporta este token Buscar por rede ou token Nenhuma rede ou token com o nome inserido foi encontrado + Pesquisar por token Suas carteiras Você não tem tokens para enviar. Compre ou Receba tokens na sua conta. Token para pagamento @@ -235,6 +242,7 @@ Backup Autenticação biométrica Compra iniciada! Por favor, aguarde até 60 minutos. Você pode rastrear o status pelo email. + Selecione a rede para comprar %s Para continuar a compra você será redirecionado do aplicativo Nova Wallet para %s Continuar no navegador? Equilibrar nós automaticamente @@ -968,6 +976,8 @@ Ao ativar as notificações push, você concorda com nossos %s e %s Por favor, tente novamente mais tarde acessando as configurações de notificação na aba Configurações Não perca nada! + Selecione a rede para receber %s + Copiar Endereço Cole o json ou faça upload do arquivo… Fazer upload de arquivo Restaurar JSON @@ -1125,6 +1135,7 @@ Selecione faixas para %d de %d Endereço ou w3n + Selecione a rede para enviar %s O destinatário é uma conta do sistema. Não é controlado por nenhuma empresa ou indivíduo.\nVocê ainda deseja realizar esta transferência? Os tokens serão perdidos Dar autoridade para @@ -1534,6 +1545,7 @@ Digite outra quantidade Para pagar a taxa de rede com %s, a Nova fará automaticamente a troca de %s por %s para manter o saldo mínimo de %s na sua conta. Uma taxa de rede cobrada pela blockchain para processar e validar quaisquer transações. Pode variar dependendo das condições da rede ou velocidade da transação. + Selecione a rede para trocar %s O pool não tem liquidez suficiente para a troca Diferença de preço refere-se à diferença de preço entre dois ativos diferentes. Ao fazer uma troca em cripto, a diferença de preço geralmente é entre o preço do ativo que você está trocando e o preço do ativo com o qual você está trocando. Diferença de preço @@ -1626,6 +1638,7 @@ Comprar com Receber Receber %s + Envie somente o token %1$s e tokens na rede %2$s para este endereço, ou você pode perder seus fundos Enviar Trocar Ativos diff --git a/common/src/main/res/values-ru/strings.xml b/common/src/main/res/values-ru/strings.xml index cd1f87d762..b1f4666312 100644 --- a/common/src/main/res/values-ru/strings.xml +++ b/common/src/main/res/values-ru/strings.xml @@ -173,6 +173,10 @@ Вы достигли лимита добавленных прокси (%s) в %s . Удалите прокси, чтобы добавить новые. Достигнуто максимальное количество прокси Добавленные пользовательские сети\nпоявятся здесь + Цветной + Внешний вид + иконки токенов + Белый Введенный адрес контракта уже добавлен в Nova как токен %s. Введенный адрес контракта присутствует в Nova как токен %s. Вы уверены, что хотите изменить его? Этот токен уже добавлен @@ -185,6 +189,8 @@ Введите адрес контракта Введите число десятичных знаков Введите символ + Сети + Токены Добавить токен Адрес контракта Число десятичных знаков @@ -207,6 +213,7 @@ Ledger не поддерживает этот токен Поиск по названию сети или токена Токены и сети с указанным именем\nне найдены + Поиск по токену Ваши кошельки У вас нет токенов для отправки.\nКупите или получите токены\nна свой аккаунт. Токен для оплаты @@ -235,6 +242,7 @@ Бэкап Биометрия Покупка совершена! Ожидайте до 60 минут. Вы можете отслеживать статус по электронной почте. + Выберите сеть для покупки %s Для продолжения покупки вы будете перенаправлены из приложения Nova Wallet на сайт %s Продолжить в браузере? Автоматическая балансировка нод @@ -982,6 +990,8 @@ Включая push-уведомления, вы соглашаетесь с нашими %s и %s Повторите попытку позже, открыв настройки уведомлений на вкладке «Настройки» Не пропустите ничего! + Выберите сеть для получения %s + Скопировать адрес Вставьте json строку или загрузите файл… Загрузите файл JSON для восстановления @@ -1141,6 +1151,7 @@ Выберите треки для %d из %d Адрес или w3n + Выберите сеть для отправки %s Получатель является системным аккаунтом. Этот аккаунт не контролируется какой-либо компанией или частным лицом. \nВы уверены, что все еще хотите выполнить данный перевод? Токены будут потеряны Выдать полномочия аккаунту @@ -1554,6 +1565,7 @@ Введите другую сумму Чтобы оплатить комиссию сети с помощью %s, Nova автоматически обменяет %s на %s, чтобы поддерживать минимальный %s баланс вашей учетной записи. Комиссия сети, взимается блокчейном за обработку и проверку транзакций. Может варьироваться в зависимости от условий сети или скорости транзакции. + Выберите сеть для обмена %s В пуле недостаточно ликвидности для обмена Разница в цене представляет собой разницу между двумя различными активами. При обмене криптовалюты под разницей в цене обычно имеется ввиду разница между ценой актива, которую вы получаете и ценой актива, которую вы платите. Разница в цене @@ -1646,6 +1658,7 @@ Купить с Получить Получить %s + Отправляйте только токен %1$s и токены в сети %2$s на этот адрес, иначе вы можете потерять свои средства Перевести Обменять Активы diff --git a/common/src/main/res/values-tr/strings.xml b/common/src/main/res/values-tr/strings.xml index aa73d206fc..919eab0a59 100644 --- a/common/src/main/res/values-tr/strings.xml +++ b/common/src/main/res/values-tr/strings.xml @@ -173,6 +173,10 @@ %s\'da eklenen maksimum proxy (%s) limitine ulaştınız. Yeni eklemeler yapabilmek için proxy\'leri kaldırın. Maksimum proxy sayısına ulaşıldı Eklenen özel ağlar\nburada görünecek + Renkli + Görünüm + token simgeleri + Beyaz Girilen sözleşme adresi Nova\'da zaten %s tokeni olarak bulunmaktadır. Girilen sözleşme adresi Nova\'da zaten %s tokeni olarak bulunmaktadır. Değiştirmek istediğinize emin misiniz? Bu token zaten var @@ -185,6 +189,8 @@ Sözleşme adresi girin Ondalık sayısını girin Sembol girin + Ağlar + Tokenler Token ekle Sözleşme adresi Ondalıklar @@ -207,6 +213,7 @@ Ledger bu token\'i desteklemiyor Ağ veya token adına göre ara Girilen adla herhangi bir ağ veya token bulunamadı + Tokene göre ara Cüzdanlarınız Göndermek için token\'ınız yok.\nHesabınıza token alın veya alın. Ödeme yapılacak Token @@ -235,6 +242,7 @@ Yedekleme Biyometrik Doğrulama Satın alma başlatıldı! Lütfen 60 dakika kadar bekleyin. Durumu e-postadan takip edebilirsiniz. + Satın alma için ağ seçin %s Satın alma işlemine devam etmek için Nova Wallet uygulamasından %s\'a yönlendirileceksiniz Tarayıcıda devam et? Otomatik denge düğümleri @@ -968,6 +976,8 @@ Bildirimleri etkinleştirmekle, %s ve %s kabul etmiş olursunuz Lütfen, Ayarlar sekmesinden bildirim ayarlarına erişerek daha sonra tekrar deneyin Hiçbir şeyi kaçırmayın! + Alma için ağ seçin %s + Adresi Kopyala Json yapıştırın ya da dosya yükleyin... Dosya yükle JSON Kurtar @@ -1125,6 +1135,7 @@ İçin şarkıları seçin %d / %d Adres veya w3n + Gönderme için ağ seçin %s Alıcı, bir sistem hesabıdır. Bir şirket veya birey tarafından kontrol edilmez.\nBu transferi gerçekleştirmek istediğinize emin misiniz? Token\'lar kaybolacak Yetki ver @@ -1534,6 +1545,7 @@ Başka bir miktar girin %s ile ağ ücreti ödemek için, Nova otomatik olarak hesabınızın minimum %s bakiyesini korumak için %s\'i %s\'ye dönüştürecektir. Herhangi bir işlemi işlemek ve doğrulamak için blockchain tarafından alınan ağ ücretleri. Ağ koşullarına veya işlem hızına bağlı olarak değişebilir. + Takas için ağ seçin %s Havuzda takas için yeterli likidite yok Fiyat farkı, iki farklı varlık arasındaki fiyat farkını ifade eder. Kripto takas yaparken, fiyat farkı genellikle takas ettiğiniz varlığın fiyatı ile takas ettiğiniz varlığın fiyatı arasındaki farktır. Fiyat farkı @@ -1626,6 +1638,7 @@ ile Satın al Al %s al + Bu adrese yalnızca %1$s token ve %2$s ağındaki tokenleri gönderin, aksi takdirde paranızı kaybedebilirsiniz Gönder Takas et Varlıklar diff --git a/common/src/main/res/values-vi/strings.xml b/common/src/main/res/values-vi/strings.xml index 6ebc3b7831..50cb3a328b 100644 --- a/common/src/main/res/values-vi/strings.xml +++ b/common/src/main/res/values-vi/strings.xml @@ -173,6 +173,10 @@ Bạn đã đạt đến giới hạn %s proxy được thêm vào %s. Xóa proxy để thêm proxy mới. Đã đạt đến số lượng proxy tối đa Các mạng tùy chỉnh đã thêm\nsẽ xuất hiện ở đây + Đã tô màu + Giao diện + biểu tượng token + Trắng Địa chỉ hợp đồng đã nhập có sẵn trong Nova là token %s. Địa chỉ hợp đồng đã nhập có sẵn trong Nova là token %s. Bạn có chắc chắn muốn thay đổi không? Token này đã tồn tại @@ -185,6 +189,8 @@ Nhập địa chỉ hợp đồng Nhập số thập phân Nhập ký hiệu + Mạng + Token Thêm token Địa chỉ hợp đồng Số thập phân @@ -207,6 +213,7 @@ Ledger không hỗ trợ token này Tìm kiếm theo mạng hoặc token Không tìm thấy mạng hoặc token nào với\ntên đã nhập + Tìm kiếm theo token Ví của bạn Bạn không có token để gửi.\nMua hoặc Nhận token vào\ntài khoản của bạn. Token để thanh toán @@ -235,6 +242,7 @@ Sao lưu Xác thực sinh trắc học Mua hàng đã được khởi tạo! Vui lòng đợi tối đa 60 phút. Bạn có thể theo dõi trạng thái trong email. + Chọn mạng để mua %s Để tiếp tục mua hàng, bạn sẽ được chuyển hướng từ ứng dụng Nova Wallet tới %s Tiếp tục trong trình duyệt? Tự động cân bằng nodes @@ -961,6 +969,8 @@ Bằng việc bật thông báo đẩy, bạn đồng ý với %s và %s của chúng tôi Vui lòng thử lại sau bằng cách truy cập cài đặt thông báo từ tab Cài đặt Đừng bỏ lỡ điều gì! + Chọn mạng để nhận %s + Sao chép Địa chỉ Dán mã JSON hoặc tải lên tệp... Tải lên tệp Khôi phục JSON @@ -1117,6 +1127,7 @@ Chọn track cho %d trong %d Địa chỉ hoặc w3n + Chọn mạng để gửi %s Người nhận là một tài khoản hệ thống. Nó không được kiểm soát bởi bất kỳ công ty hoặc cá nhân nào.\nBạn có chắc chắn vẫn muốn thực hiện chuyển khoản này không? Token sẽ bị mất Cấp quyền cho @@ -1524,6 +1535,7 @@ Nhập số tiền khác Để thanh toán phí mạng bằng %s, Nova sẽ tự động hoán đổi %s thành %s để duy trì số dư tối thiểu %s trong tài khoản của bạn. Một khoản phí mạng được tính bởi blockchain để xử lý và xác nhận bất kỳ giao dịch nào. Có thể thay đổi tùy thuộc vào điều kiện mạng hoặc tốc độ giao dịch. + Chọn mạng để hoán đổi %s Pool không có đủ thanh khoản để thực hiện hoán đổi Sự khác biệt về giá đề cập đến sự chênh lệch giá giữa hai tài sản khác nhau. Khi thực hiện hoán đổi trong tiền điện tử, sự khác biệt về giá thường là sự chênh lệch giữa giá của tài sản mà bạn đang hoán đổi và giá của tài sản mà bạn đang hoán đổi. Sự khác biệt về giá @@ -1616,6 +1628,7 @@ Mua với Nhận Nhận %s + Chỉ gửi token %1$s và các token trong mạng %2$s tới địa chỉ này, nếu không bạn có thể mất tiền Gửi Hoán đổi Tài sản diff --git a/common/src/main/res/values-zh-rCN/strings.xml b/common/src/main/res/values-zh-rCN/strings.xml index cc1c960d19..dc2ebea500 100644 --- a/common/src/main/res/values-zh-rCN/strings.xml +++ b/common/src/main/res/values-zh-rCN/strings.xml @@ -173,6 +173,10 @@ 您已达到在%s中添加的代理的上限%s。移除代理以添加新代理。 已达到代理最大数量 添加的自定义网络会显示在这里 + 彩色图标 + 外观 + 代币图标 + 白色图标 输入的合约地址已作为%s代币存在于Nova中。 输入的合约地址已作为%s代币存在于Nova中。您确定要修改它吗? 该代币已存在 @@ -185,6 +189,8 @@ 输入合约地址 输入小数 输入符号 + 网络 + 代币 添加代币 合约地址 小数点 @@ -207,6 +213,7 @@ Ledger 不支持此代币 按网络或代币搜索 没有找到输入名称的网络或代币 + 按代币搜索 你的钱包 你没有要发送的代币。购买或接收代币到你的账户。 要支付的代币 @@ -235,6 +242,7 @@ 备份 生物认证 购买已启动!请等待最多 60 分钟。你可以在电子邮件上追踪状态。 + 选择购买%s的网络 为了继续购买,你将从 Nova Wallet 应用被重定向到 %s 在浏览器中继续? 自动平衡节点 @@ -961,6 +969,8 @@ 启用推送通知,即表示您同意我们的 %s 和 %s 请稍后再试,通过设置选项卡中的通知设置访问 不要错过任何事情! + 选择接收%s的网络 + 复制地址 粘贴 json 字符串或上传文件… 上传文件 恢复 JSON @@ -1117,6 +1127,7 @@ 选择曲目 %d / %d 地址或w3n + 选择发送%s的网络 收件人是一个系统账户。它不受任何公司或个人控制。您确定仍然要执行此转账吗? 代币将会丢失 授权给 @@ -1524,6 +1535,7 @@ 输入其他金额 为了支付网络费用,Nova将自动将%s兑换为%s,以保持您账户的最低%s余额。 区块链收取的网络费用,用于处理和验证任何交易。可能会根据网络状况或交易速度而变化。 + 选择交换%s的网络 池子没有足够的流动性进行交换 价格差异指的是两种不同资产之间的价格差。在加密货币交换中,价格差异通常是您要交换的资产的价格与您交换的资产的价格之间的差异。 价格差异 @@ -1616,6 +1628,7 @@ 用...购买 接收 接收 %s + 仅将%1$s代币和%2$s网络中的代币发送到此地址,否则您可能会失去资金 发送 兑换 资产 From b5e05432e985ff8f874703a05de02960050a6af5 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 8 Nov 2024 11:23:54 +0100 Subject: [PATCH 64/78] Fixed assets background glitch on search - Add fallback asset icon --- .../presenatation/chain/ChainUi.kt | 5 ++-- .../balance/common/AssetTokensDecoration.kt | 2 +- .../common/holders/NetworkAssetViewHolder.kt | 5 ++-- .../holders/TokenAssetGroupViewHolder.kt | 3 ++- .../common/holders/TokenAssetViewHolder.kt | 3 ++- .../balance/detail/BalanceDetailFragment.kt | 3 ++- .../manage/chain/ManageChainTokensFragment.kt | 3 ++- .../main/res/layout/fragment_asset_search.xml | 26 +++++++++---------- .../presentation/view/SwapAssetView.kt | 3 ++- .../presentation/views/SwapAmountInputView.kt | 3 ++- .../view/amount/ChooseAmountInputView.kt | 3 ++- 11 files changed, 34 insertions(+), 25 deletions(-) diff --git a/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt b/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt index 7e38f07a7d..dc883f4cc6 100644 --- a/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt +++ b/feature-account-api/src/main/java/io/novafoundation/nova/feature_account_api/presenatation/chain/ChainUi.kt @@ -12,6 +12,7 @@ import io.novafoundation.nova.common.presentation.fallbackIcon import io.novafoundation.nova.common.presentation.getAssetIconOrFallback import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.common.utils.images.asIcon +import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.feature_account_api.R import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain @@ -43,8 +44,8 @@ fun ImageLoader.loadChainIconToTarget(icon: String?, context: Context, target: ( this.enqueue(request) } -fun ImageView.loadTokenIcon(icon: String?, imageLoader: ImageLoader) { - load(icon, imageLoader) { +fun ImageView.setTokenIcon(icon: Icon, imageLoader: ImageLoader) { + setIcon(icon, imageLoader) { fallback(ASSET_ICON_PLACEHOLDER) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt index 3c0f5a67ea..1be9269edd 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetTokensDecoration.kt @@ -173,7 +173,7 @@ class AssetTokensDecoration( val parentTranslationY = parent?.itemView?.translationY ?: 0f val childTranslationY = lastChild?.itemView?.translationY ?: 0f - val top = (parent?.itemView?.bottom ?: recyclerView.top) + parentTranslationY + val top = (parent?.itemView?.bottom ?: 0) + parentTranslationY val bottom = (lastChild?.itemView?.bottom?.toFloat() ?: top).coerceAtLeast(top) val left = parent?.itemView?.left ?: lastChild?.itemView?.left ?: recyclerView.left val right = parent?.itemView?.right ?: lastChild?.itemView?.right ?: recyclerView.right diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt index 272b16dfe9..f36f7d4220 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt @@ -5,6 +5,7 @@ import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextColorRes +import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.NetworkAssetUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel @@ -22,8 +23,8 @@ class NetworkAssetViewHolder( fun bind(networkAsset: NetworkAssetUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { val asset = networkAsset.asset - itemAssetImage.setIcon(networkAsset.icon, imageLoader) - + itemAssetImage.setTokenIcon(networkAsset.icon, imageLoader) + bindPriceInfo(asset) bindRecentChange(asset) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt index d13f981843..13cb43ce4c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt @@ -7,6 +7,7 @@ import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableParentViewHolder import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem import io.novafoundation.nova.common.utils.setTextColorRes +import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import kotlinx.android.synthetic.main.item_token_asset_group.view.itemAssetTokenGroupBalance @@ -26,7 +27,7 @@ class TokenAssetGroupViewHolder( fun bind(tokenGroup: TokenGroupUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { expandableItem = tokenGroup - itemTokenGroupAssetImage.setIcon(tokenGroup.tokenIcon, imageLoader) + itemTokenGroupAssetImage.setTokenIcon(tokenGroup.tokenIcon, imageLoader) bindPriceRate(tokenGroup) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt index ec14307d77..6ecec99a79 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt @@ -7,6 +7,7 @@ import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableChildViewHolder import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.feature_account_api.presenatation.chain.loadChainIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel @@ -28,7 +29,7 @@ class TokenAssetViewHolder( expandableItem = tokenAsset val asset = tokenAsset.asset - itemTokenAssetImage.setIcon(tokenAsset.assetIcon, imageLoader) + itemTokenAssetImage.setTokenIcon(tokenAsset.assetIcon, imageLoader) itemTokenAssetChainIcon.loadChainIcon(tokenAsset.chain.icon, imageLoader) itemTokenAssetChainName.text = tokenAsset.chain.name diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt index 2c6c968608..9d61e46667 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt @@ -12,6 +12,7 @@ import io.novafoundation.nova.common.utils.applyBarMargin import io.novafoundation.nova.common.utils.hideKeyboard import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextColorRes +import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent @@ -120,7 +121,7 @@ class BalanceDetailFragment : BaseFragment() { } viewModel.assetDetailsModel.observe { asset -> - balanceDetailTokenIcon.setIcon(asset.assetIcon, imageLoader) + balanceDetailTokenIcon.setTokenIcon(asset.assetIcon, imageLoader) balanceDetailTokenName.text = asset.token.configuration.symbol.value balanceDetailRate.text = asset.token.rate diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt index fc68f835a2..5408efe10f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt @@ -9,6 +9,7 @@ import coil.ImageLoader import io.novafoundation.nova.common.base.BaseBottomSheetFragment import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.images.setIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent @@ -58,7 +59,7 @@ class ManageChainTokensFragment : override fun subscribe(viewModel: ManageChainTokensViewModel) { viewModel.headerModel.observe { headerModel -> - manageChainTokenIcon.setIcon(headerModel.icon, imageLoader) + manageChainTokenIcon.setTokenIcon(headerModel.icon, imageLoader) manageChainTokenSymbol.text = headerModel.symbol manageChainTokenSubtitle.text = headerModel.networks } diff --git a/feature-assets/src/main/res/layout/fragment_asset_search.xml b/feature-assets/src/main/res/layout/fragment_asset_search.xml index 96792b00d3..204fda8755 100644 --- a/feature-assets/src/main/res/layout/fragment_asset_search.xml +++ b/feature-assets/src/main/res/layout/fragment_asset_search.xml @@ -1,37 +1,37 @@ + android:orientation="vertical"> + android:hint="@string/assets_search_hint" /> + android:visibility="gone" /> \ No newline at end of file diff --git a/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt b/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt index dfd7591b82..5725908399 100644 --- a/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt +++ b/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt @@ -14,6 +14,7 @@ import io.novafoundation.nova.common.utils.setTextOrHide import io.novafoundation.nova.common.view.shape.getInputBackground import io.novafoundation.nova.feature_account_api.presenatation.chain.ChainUi import io.novafoundation.nova.feature_account_api.presenatation.chain.loadChainIcon +import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon import io.novafoundation.nova.feature_swap_api.R import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel import kotlinx.android.synthetic.main.view_swap_asset.view.swapAssetAmount @@ -48,7 +49,7 @@ class SwapAssetView @JvmOverloads constructor( } private fun setAssetImageUrl(icon: Icon) { - swapAssetImage.setIcon(icon, imageLoader) + swapAssetImage.setTokenIcon(icon, imageLoader) swapAssetImage.setBackgroundResource(R.drawable.bg_token_container) } diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt index 2362cb1a09..40af54a88c 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt @@ -14,6 +14,7 @@ import io.novafoundation.nova.common.utils.images.setIconOrMakeGone import io.novafoundation.nova.common.utils.setImageTint import io.novafoundation.nova.common.view.shape.getInputBackground import io.novafoundation.nova.common.view.shape.getInputBackgroundError +import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon import io.novafoundation.nova.feature_swap_impl.R import io.novafoundation.nova.feature_swap_impl.presentation.main.input.SwapAmountInputMixin.SwapInputAssetModel import io.novafoundation.nova.feature_wallet_api.presentation.mixin.amountChooser.AmountChooserMixinBase.AmountErrorState @@ -83,7 +84,7 @@ class SwapAmountInputView @JvmOverloads constructor( return when (icon) { is SwapInputAssetModel.SwapAssetIcon.Chosen -> { swapAmountInputImage.setImageTint(null) - swapAmountInputImage.setIcon(icon.assetIcon, imageLoader) + swapAmountInputImage.setTokenIcon(icon.assetIcon, imageLoader) swapAmountInputImage.setBackgroundResource(R.drawable.bg_token_container) } diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt index 92fb7292de..834149be82 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt @@ -11,6 +11,7 @@ import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextOrHide import io.novafoundation.nova.common.view.shape.getInputBackground +import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon import io.novafoundation.nova.feature_wallet_api.R import io.novafoundation.nova.feature_wallet_api.presentation.model.ChooseAmountInputModel import kotlinx.android.synthetic.main.view_choose_amount_input.view.chooseAmountInputFiat @@ -40,7 +41,7 @@ class ChooseAmountInputView @JvmOverloads constructor( } fun loadAssetImage(icon: Icon) { - chooseAmountInputImage.setIcon(icon, imageLoader) + chooseAmountInputImage.setTokenIcon(icon, imageLoader) } fun setAssetName(name: String) { From 5389075cf8fe9d58aa1f02ae52f316af686a8602 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 8 Nov 2024 11:26:24 +0100 Subject: [PATCH 65/78] Update NetworkAssetViewHolder.kt --- .../balance/common/holders/NetworkAssetViewHolder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt index f36f7d4220..191a473641 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt @@ -24,7 +24,7 @@ class NetworkAssetViewHolder( fun bind(networkAsset: NetworkAssetUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { val asset = networkAsset.asset itemAssetImage.setTokenIcon(networkAsset.icon, imageLoader) - + bindPriceInfo(asset) bindRecentChange(asset) From fdde1cf81f1c4bd61b76c6fdc3449808997d6213 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Fri, 8 Nov 2024 11:27:21 +0100 Subject: [PATCH 66/78] Run ktlint --- .../balance/common/holders/NetworkAssetViewHolder.kt | 1 - .../balance/common/holders/TokenAssetGroupViewHolder.kt | 1 - .../presentation/balance/common/holders/TokenAssetViewHolder.kt | 1 - .../presentation/balance/detail/BalanceDetailFragment.kt | 1 - .../tokens/manage/chain/ManageChainTokensFragment.kt | 1 - .../nova/feature_swap_api/presentation/view/SwapAssetView.kt | 1 - .../feature_swap_impl/presentation/views/SwapAmountInputView.kt | 1 - .../presentation/view/amount/ChooseAmountInputView.kt | 1 - 8 files changed, 8 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt index 191a473641..4a9b2344bf 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt @@ -3,7 +3,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder -import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon import io.novafoundation.nova.feature_assets.presentation.balance.common.BalanceListAdapter diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt index 13cb43ce4c..02e6a972e6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt @@ -3,7 +3,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder -import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableParentViewHolder import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem import io.novafoundation.nova.common.utils.setTextColorRes diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt index 6ecec99a79..0596f3a41e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt @@ -3,7 +3,6 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common.holder import android.view.View import coil.ImageLoader import io.novafoundation.nova.common.list.GroupedListHolder -import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.recyclerView.expandable.ExpandableChildViewHolder import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableChildItem import io.novafoundation.nova.feature_account_api.presenatation.chain.loadChainIcon diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt index 9d61e46667..eb666f3f80 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/detail/BalanceDetailFragment.kt @@ -10,7 +10,6 @@ import io.novafoundation.nova.common.base.BaseFragment import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.applyBarMargin import io.novafoundation.nova.common.utils.hideKeyboard -import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon import io.novafoundation.nova.feature_assets.R diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt index 5408efe10f..c593c40058 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/tokens/manage/chain/ManageChainTokensFragment.kt @@ -8,7 +8,6 @@ import androidx.core.os.bundleOf import coil.ImageLoader import io.novafoundation.nova.common.base.BaseBottomSheetFragment import io.novafoundation.nova.common.di.FeatureUtils -import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon import io.novafoundation.nova.feature_assets.R import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi diff --git a/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt b/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt index 5725908399..5bdeb3da91 100644 --- a/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt +++ b/feature-swap-api/src/main/java/io/novafoundation/nova/feature_swap_api/presentation/view/SwapAssetView.kt @@ -8,7 +8,6 @@ import coil.ImageLoader import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.WithContextExtensions import io.novafoundation.nova.common.utils.images.Icon -import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextColorRes import io.novafoundation.nova.common.utils.setTextOrHide import io.novafoundation.nova.common.view.shape.getInputBackground diff --git a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt index 40af54a88c..9255a2ff4e 100644 --- a/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt +++ b/feature-swap-impl/src/main/java/io/novafoundation/nova/feature_swap_impl/presentation/views/SwapAmountInputView.kt @@ -9,7 +9,6 @@ import coil.ImageLoader import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.WithContextExtensions import io.novafoundation.nova.common.utils.images.Icon -import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.images.setIconOrMakeGone import io.novafoundation.nova.common.utils.setImageTint import io.novafoundation.nova.common.view.shape.getInputBackground diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt index 834149be82..a9a9102553 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/amount/ChooseAmountInputView.kt @@ -8,7 +8,6 @@ import androidx.constraintlayout.widget.ConstraintLayout import coil.ImageLoader import io.novafoundation.nova.common.di.FeatureUtils import io.novafoundation.nova.common.utils.images.Icon -import io.novafoundation.nova.common.utils.images.setIcon import io.novafoundation.nova.common.utils.setTextOrHide import io.novafoundation.nova.common.view.shape.getInputBackground import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon From e52aa1d39b07292b6c888dbf27c043c3db369e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Muller?= Date: Mon, 11 Nov 2024 06:16:55 +0100 Subject: [PATCH 67/78] Remove Multidex declaration (#1716) Since the min SDK is 24, it is no longer necessary to use the Multidex library. The Robolectric-specific dependency is actually no longer used, but still declared in Gradle. See the following for more info: https://developer.android.com/build/multidex#mdex-on-l --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index 82a2016493..470200fc98 100644 --- a/build.gradle +++ b/build.gradle @@ -176,7 +176,6 @@ buildscript { jUnitDep = "junit:junit:$junitVersion" mockitoDep = "org.mockito:mockito-inline:$mockitoVersion" robolectricDep = "org.robolectric:robolectric:$robolectricVersion" - robolectricMultidexDep = "org.robolectric:shadows-multidex:$robolectricVersion" archCoreTestDep = "androidx.arch.core:core-testing:$architectureComponentVersion" progressButtonDep = "com.github.razir.progressbutton:progressbutton:$progressButtonsVersion" From a30f98a17376662674b8a5b598b35b494d7d7eb9 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Mon, 11 Nov 2024 12:20:08 +0100 Subject: [PATCH 68/78] Fixed bugs - Amount formatting - Sorting in tokens - Sorting in asset flow (network screen) - Qr code scanning - Expanding animation glitch --- .../novafoundation/nova/common/view/QrCodeView.kt | 2 +- common/src/main/res/values/strings.xml | 2 ++ .../search/ByTokensAssetSearchInteractor.kt | 15 ++++++++------- .../domain/common/TokenAssetSorting.kt | 1 + .../balance/common/BalanceListAdapter.kt | 4 +++- .../common/holders/NetworkAssetViewHolder.kt | 2 +- .../common/holders/TokenAssetViewHolder.kt | 2 +- .../balance/common/mappers/TokenAssetMappers.kt | 8 ++------ .../balance/list/BalanceListFragment.kt | 4 +++- .../balance/list/BalanceListViewModel.kt | 8 +++++--- .../balance/list/model/items/TokenAssetUi.kt | 8 ++++++++ .../balance/list/model/items/TokenGroupUi.kt | 5 +++-- .../balance/search/AssetSearchFragment.kt | 3 ++- .../balance/search/AssetSearchViewModel.kt | 7 ++++--- .../buy/flow/asset/AssetBuyFlowViewModel.kt | 8 ++++---- .../presentation/flow/asset/AssetFlowFragment.kt | 3 ++- .../presentation/flow/asset/AssetFlowViewModel.kt | 10 +++++----- .../flow/asset/AssetReceiveFlowViewModel.kt | 12 ++++++------ .../send/flow/asset/AssetSendFlowViewModel.kt | 6 +++--- .../swap/asset/AssetSwapFlowViewModel.kt | 7 +++---- .../presentation/track/TrackFormatter.kt | 3 ++- .../presentation/model/AmountFormatters.kt | 6 +++--- .../presentation/model/AmountModel.kt | 10 +++++++++- .../presentation/view/AssetSelectorBottomSheet.kt | 2 +- 24 files changed, 82 insertions(+), 56 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt b/common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt index 5606c53e80..af48b0b7a5 100644 --- a/common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt +++ b/common/src/main/java/io/novafoundation/nova/common/view/QrCodeView.kt @@ -42,7 +42,7 @@ class QrCodeView @JvmOverloads constructor( private var overlayBackground: Drawable? = null private val overlaySize = 64.dp - private val overlayQuiteZone = 4.dp + private val overlayQuiteZone = 0 private val qrPadding = 16.dpF private val centerRect: RectF = RectF() diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index 5edea2541d..b157bffc3d 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -1,6 +1,8 @@ + Select network + Search by token Copy Address diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt index 2410f2e2df..5755da513a 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/assets/search/ByTokensAssetSearchInteractor.kt @@ -55,15 +55,16 @@ class ByTokensAssetSearchInteractor( externalBalancesFlow: Flow>, coroutineScope: CoroutineScope ): Flow { - val filterFlow = assetSearchUseCase.getAvailableSwapAssets(forAsset, coroutineScope).map { availableAssetsForSwap -> - val filter: AssetSearchFilter = { asset -> - val chainAsset = asset.token.configuration + val filterFlow = assetSearchUseCase.getAvailableSwapAssets(forAsset, coroutineScope) + .map { availableAssetsForSwap -> + val filter: AssetSearchFilter = { asset -> + val chainAsset = asset.token.configuration - chainAsset.fullId in availableAssetsForSwap - } + chainAsset.fullId in availableAssetsForSwap + } - filter - } + filter + } return searchAssetsByTokensInternalFlow(queryFlow, externalBalancesFlow, filterFlow = filterFlow) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt index 53e97054f8..eb3241bee4 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt @@ -61,6 +61,7 @@ fun getTokenAssetBaseComparator( return compareByDescending(comparing) .thenByDescending { it.asset.token.configuration.isUtilityAsset } // utility assets first .thenBy { it.asset.token.configuration.symbol.value } + .then(Chain.defaultComparatorFrom(AssetWithNetwork::chain)) } fun getTokenAssetGroupBaseComparator( diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt index 6ceb773c88..4be2db2a29 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt @@ -22,6 +22,8 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.ite import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenAssetUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel +import io.novafoundation.nova.feature_wallet_api.domain.model.Asset +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain private val priceRateExtractor = { asset: AssetModel -> asset.token.rate } private val recentChangeExtractor = { asset: AssetModel -> asset.token.recentRateChange } @@ -42,7 +44,7 @@ class BalanceListAdapter( ) : ListAdapter(DiffCallback), ExpandableAdapter { interface ItemAssetHandler { - fun assetClicked(asset: AssetModel) + fun assetClicked(asset: Chain.Asset) fun tokenGroupClicked(tokenGroup: TokenGroupUi) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt index 4a9b2344bf..c743f884f2 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/NetworkAssetViewHolder.kt @@ -32,7 +32,7 @@ class NetworkAssetViewHolder( itemAssetToken.text = asset.token.configuration.symbol.value - setOnClickListener { itemHandler.assetClicked(asset) } + setOnClickListener { itemHandler.assetClicked(asset.token.configuration) } } fun bindTotal(asset: AssetModel) { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt index 0596f3a41e..5045e2854d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetViewHolder.kt @@ -36,7 +36,7 @@ class TokenAssetViewHolder( itemTokenAssetToken.text = asset.token.configuration.symbol.value - setOnClickListener { itemHandler.assetClicked(asset) } + setOnClickListener { itemHandler.assetClicked(asset.token.configuration) } } fun bindTotal(asset: AssetModel) { diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt index 7e13ddad55..49ba3823a1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/mappers/TokenAssetMappers.kt @@ -58,7 +58,7 @@ fun mapTokenAssetGroupToUi( token = balance.amount.formatTokenAmount(), fiat = balance.fiat.formatAsCurrency(assetGroup.token.currency) ).formatBalanceWithFraction(amountFormatter, R.dimen.asset_balance_fraction_size), - groupType = mapType(amountFormatter, assetGroup, assets, groupBalance) + groupType = mapType(assets) ) } @@ -80,14 +80,10 @@ private fun mapAssetsToAssetModels( } private fun mapType( - amountFormatter: AmountFormatter, - assetGroup: TokenAssetGroup, assets: List, - groupBalance: (TokenAssetGroup) -> PricedAmount ): TokenGroupUi.GroupType { return if (assets.size == 1) { - val balance = groupBalance(assetGroup) - TokenGroupUi.GroupType.SingleItem(mapAssetToAssetModel(amountFormatter, assets.first().asset, balance)) + TokenGroupUi.GroupType.SingleItem(assets.first().asset.token.configuration) } else { TokenGroupUi.GroupType.Group } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index 7601973c77..b7fec4ee90 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -25,6 +25,8 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.createF import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetsHeaderAdapter import io.novafoundation.nova.feature_assets.presentation.model.AssetModel +import io.novafoundation.nova.feature_wallet_api.domain.model.Asset +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.android.synthetic.main.fragment_balance_list.balanceListAssets import kotlinx.android.synthetic.main.fragment_balance_list.walletContainer import javax.inject.Inject @@ -142,7 +144,7 @@ class BalanceListFragment : viewModel.assetViewModeModelFlow.observe { headerAdapter.setAssetViewModeModel(it) } } - override fun assetClicked(asset: AssetModel) { + override fun assetClicked(asset: Chain.Asset) { viewModel.assetClicked(asset) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt index c6d8d940ff..824dbf2f90 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt @@ -35,12 +35,14 @@ import io.novafoundation.nova.feature_currency_api.presentation.formatters.forma import io.novafoundation.nova.feature_currency_api.presentation.formatters.simpleFormatAsCurrency import io.novafoundation.nova.feature_nft_api.data.model.Nft import io.novafoundation.nova.feature_swap_api.domain.interactor.SwapAvailabilityInteractor +import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.presentation.formatters.mapBalanceIdToUi import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_wallet_api.presentation.model.mapAmountToAmountModel import io.novafoundation.nova.feature_wallet_connect_api.domain.sessions.WalletConnectSessionsUseCase import io.novafoundation.nova.feature_wallet_connect_api.presentation.mapNumberOfActiveSessionsToUi +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.coroutines.async import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce @@ -200,10 +202,10 @@ class BalanceListViewModel( } } - fun assetClicked(asset: AssetModel) { + fun assetClicked(asset: Chain.Asset) { val payload = AssetPayload( - chainId = asset.token.configuration.chainId, - chainAssetId = asset.token.configuration.id + chainId = asset.chainId, + chainAssetId = asset.id ) router.openAssetDetails(payload) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt index 3c179a103e..e2a4b59793 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt @@ -14,4 +14,12 @@ data class TokenAssetUi( ) : AssetRvItem, ExpandableChildItem { override val itemId: String = "token_" + asset.token.configuration.fullId.toString() + + override fun equals(other: Any?): Boolean { + if (other is TokenAssetUi) { + return chain.id == other.chain.id + } + + return false + } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt index b30d917195..45bd2da6f8 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenGroupUi.kt @@ -3,8 +3,9 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list.model.it import androidx.annotation.ColorRes import io.novafoundation.nova.common.utils.images.Icon import io.novafoundation.nova.common.utils.recyclerView.expandable.items.ExpandableParentItem -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel +import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountModel +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain data class TokenGroupUi( override val itemId: String, @@ -21,6 +22,6 @@ data class TokenGroupUi( sealed interface GroupType { object Group : GroupType - data class SingleItem(val asset: AssetModel) : GroupType + data class SingleItem(val asset: Chain.Asset) : GroupType } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt index 40300d348d..a4fdee087e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt @@ -27,6 +27,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDec import io.novafoundation.nova.feature_assets.presentation.balance.common.createForAssets import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.android.synthetic.main.fragment_asset_search.searchAssetContainer import kotlinx.android.synthetic.main.fragment_asset_search.searchAssetList import kotlinx.android.synthetic.main.fragment_asset_search.searchAssetSearch @@ -110,7 +111,7 @@ class AssetSearchFragment : searchAssetSearch.searchInput.hideSoftKeyboard() } - override fun assetClicked(asset: AssetModel) { + override fun assetClicked(asset: Chain.Asset) { viewModel.assetClicked(asset) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt index 1ceb18ebe1..b93036183c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt @@ -7,6 +7,7 @@ import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ExpandableAssetsMixinFactory import io.novafoundation.nova.feature_assets.presentation.model.AssetModel +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.coroutines.flow.MutableStateFlow class AssetSearchViewModel( @@ -32,10 +33,10 @@ class AssetSearchViewModel( router.back() } - fun assetClicked(assetModel: AssetModel) { + fun assetClicked(asset: Chain.Asset) { val payload = AssetPayload( - chainId = assetModel.token.configuration.chainId, - chainAssetId = assetModel.token.configuration.id + chainId = asset.chainId, + chainAssetId = asset.id ) router.openAssetDetails(payload) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt index daf1d74dff..3bd587c92f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt @@ -16,6 +16,7 @@ import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.coroutines.flow.Flow class AssetBuyFlowViewModel( @@ -49,10 +50,9 @@ class AssetBuyFlowViewModel( return interactor.buyAssetSearch(query, externalBalancesFlow) } - override fun assetClicked(assetModel: AssetModel) { - validate(assetModel) { - val chainAsset = assetModel.token.configuration - buyMixin.buyClicked(chainAsset) + override fun assetClicked(asset: Chain.Asset) { + validate(asset) { + buyMixin.buyClicked(asset) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt index 61c5ce5b32..e18be62fce 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt @@ -26,6 +26,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDec import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.receive.view.LedgerNotSupportedWarningBottomSheet +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import javax.inject.Inject import kotlinx.android.synthetic.main.fragment_asset_flow_search.assetFlowList import kotlinx.android.synthetic.main.fragment_asset_flow_search.assetFlowPlaceholder @@ -113,7 +114,7 @@ abstract class AssetFlowFragment : } } - override fun assetClicked(asset: AssetModel) { + override fun assetClicked(asset: Chain.Asset) { viewModel.assetClicked(asset) assetFlowToolbar.searchField.hideSoftKeyboard() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index d00936a90d..45bbc983df 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -28,6 +28,7 @@ import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -87,7 +88,7 @@ abstract class AssetFlowViewModel( abstract fun searchAssetsFlow(): Flow - abstract fun assetClicked(assetModel: AssetModel) + abstract fun assetClicked(asset: Chain.Asset) abstract fun tokenClicked(tokenGroup: TokenGroupUi) @@ -106,12 +107,11 @@ abstract class AssetFlowViewModel( return assets.map { mapTokenAssetGroupToUi(amountFormatter, assetIconProvider, it.key, assets = it.value) } } - internal fun validate(assetModel: AssetModel, onAccept: (AssetModel) -> Unit) { + internal fun validate(asset: Chain.Asset, onAccept: (Chain.Asset) -> Unit) { launch { val metaAccount = accountUseCase.getSelectedMetaAccount() - val chainAsset = assetModel.token.configuration - controllableAssetCheck.check(metaAccount, chainAsset) { - onAccept(assetModel) + controllableAssetCheck.check(metaAccount, asset) { + onAccept(asset) } } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt index c33bee7613..f829267d69 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt @@ -16,6 +16,7 @@ import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFl import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.coroutines.flow.Flow class AssetReceiveFlowViewModel( @@ -45,9 +46,9 @@ class AssetReceiveFlowViewModel( return interactor.searchReceiveAssetsFlow(query, externalBalancesFlow) } - override fun assetClicked(assetModel: AssetModel) { - validate(assetModel) { - openNextScreen(assetModel) + override fun assetClicked(asset: Chain.Asset) { + validate(asset) { + openNextScreen(asset) } } @@ -59,9 +60,8 @@ class AssetReceiveFlowViewModel( } } - private fun openNextScreen(assetModel: AssetModel) { - val chainAsset = assetModel.token.configuration - val assetPayload = AssetPayload(chainAsset.chainId, chainAsset.id) + private fun openNextScreen(asset: Chain.Asset) { + val assetPayload = AssetPayload(asset.chainId, asset.id) router.openReceive(assetPayload) } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt index 03f77014a9..d213342536 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt @@ -28,6 +28,7 @@ import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.coroutines.flow.Flow class AssetSendFlowViewModel( @@ -58,9 +59,8 @@ class AssetSendFlowViewModel( return interactor.sendAssetSearch(query, externalBalancesFlow) } - override fun assetClicked(assetModel: AssetModel) { - val chainAsset = assetModel.token.configuration - val assetPayload = AssetPayload(chainAsset.chainId, chainAsset.id) + override fun assetClicked(asset: Chain.Asset) { + val assetPayload = AssetPayload(asset.chainId, asset.id) router.openSend(SendPayload.SpecifiedOrigin(assetPayload)) } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt index 022222f7cd..820d286688 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/swap/asset/AssetSwapFlowViewModel.kt @@ -24,7 +24,6 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.ite import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowViewModel import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.swap.executor.SwapFlowExecutor import io.novafoundation.nova.feature_assets.presentation.swap.network.NetworkSwapFlowPayload import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor @@ -32,6 +31,7 @@ import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_swap_api.domain.interactor.SwapAvailabilityInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import io.novafoundation.nova.feature_wallet_api.presentation.model.fullChainAssetId +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch @@ -85,10 +85,9 @@ class AssetSwapFlowViewModel( ) } - override fun assetClicked(assetModel: AssetModel) { + override fun assetClicked(asset: Chain.Asset) { launch { - val chainAsset = assetModel.token.configuration - swapFlowExecutor.openNextScreen(viewModelScope, chainAsset) + swapFlowExecutor.openNextScreen(viewModelScope, asset) } } diff --git a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt index e0897e4fcf..36a475bdb9 100644 --- a/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt +++ b/feature-governance-impl/src/main/java/io/novafoundation/nova/feature_governance_impl/presentation/track/TrackFormatter.kt @@ -1,5 +1,6 @@ package io.novafoundation.nova.feature_governance_impl.presentation.track +import io.novafoundation.nova.common.data.model.AssetIconMode import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.resources.ResourceManager import io.novafoundation.nova.common.resources.formatListPreview @@ -37,7 +38,7 @@ class RealTrackFormatter( return when (trackCategorizer.typeOf(track.name)) { TrackType.ROOT -> TrackModel( name = resourceManager.getString(R.string.referendum_track_root), - icon = assetIconProvider.getAssetIconOrFallback(asset, fallbackIcon = R.drawable.ic_block.asIcon()), + icon = assetIconProvider.getAssetIconOrFallback(asset, iconMode = AssetIconMode.WHITE, fallbackIcon = R.drawable.ic_block.asIcon()), ) TrackType.WHITELISTED_CALLER -> TrackModel( diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt index 0999e2b8a4..ce9a752716 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountFormatters.kt @@ -11,15 +11,15 @@ import io.novafoundation.nova.feature_wallet_api.R interface AmountFormatter { - fun formatBalanceWithFraction(amount: CharSequence, @DimenRes floatAmountSize: Int): CharSequence + fun formatBalanceWithFraction(unformattedAmount: CharSequence, @DimenRes floatAmountSize: Int): CharSequence } class RealAmountFormatter( private val resourceManager: ResourceManager ) : AmountFormatter { - override fun formatBalanceWithFraction(amount: CharSequence, @DimenRes floatAmountSize: Int): CharSequence { - val amountWithFraction = amount.toAmountWithFraction() + override fun formatBalanceWithFraction(unformattedAmount: CharSequence, @DimenRes floatAmountSize: Int): CharSequence { + val amountWithFraction = unformattedAmount.toAmountWithFraction() val textColor = resourceManager.getColor(R.color.text_secondary) val colorSpan = ForegroundColorSpan(textColor) diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt index 38140a1b6f..ec3e64b021 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt @@ -14,7 +14,15 @@ import java.math.RoundingMode data class AmountModel( val token: CharSequence, val fiat: CharSequence? -) +) { + + // Override it since SpannableString is not equals by content + override fun equals(other: Any?): Boolean { + return other is AmountModel + && other.token.toString() == token.toString() + && other.fiat?.toString() == fiat?.toString() + } +} enum class AmountSign(val signSymbol: String) { NONE(""), NEGATIVE("-"), POSITIVE("+") diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt index 7e382e1267..13fa413f1f 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/view/AssetSelectorBottomSheet.kt @@ -33,7 +33,7 @@ class AssetSelectorBottomSheet( override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setTitle(R.string.wallet_assets) + setTitle(R.string.select_network_title) setSubtitle(null) } From 072a6cd5e29b3d92b529aa6c0b90410f5da446ab Mon Sep 17 00:00:00 2001 From: valentun Date: Mon, 11 Nov 2024 18:18:22 +0700 Subject: [PATCH 69/78] Fix - outdated asset group info was used to handle clicks --- .../balance/common/BalanceListAdapter.kt | 9 ++-- .../holders/TokenAssetGroupViewHolder.kt | 50 +++++++++++++++---- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt index 4be2db2a29..c6ab404aa6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/BalanceListAdapter.kt @@ -32,6 +32,7 @@ private val amountExtractor = { asset: AssetModel -> asset.amount } private val tokenGroupPriceRateExtractor = { group: TokenGroupUi -> group.rate } private val tokenGroupRecentChangeExtractor = { group: TokenGroupUi -> group.recentRateChange } private val tokenGroupAmountExtractor = { group: TokenGroupUi -> group.balance } +private val tokenGroupTypeExtractor = { group: TokenGroupUi -> group.groupType } const val TYPE_NETWORK_GROUP = 0 const val TYPE_NETWORK_ASSET = 1 @@ -53,7 +54,7 @@ class BalanceListAdapter( return when (viewType) { TYPE_NETWORK_GROUP -> NetworkAssetGroupViewHolder(parent.inflateChild(R.layout.item_network_asset_group)) TYPE_NETWORK_ASSET -> NetworkAssetViewHolder(parent.inflateChild(R.layout.item_network_asset), imageLoader) - TYPE_TOKEN_GROUP -> TokenAssetGroupViewHolder(parent.inflateChild(R.layout.item_token_asset_group), imageLoader) + TYPE_TOKEN_GROUP -> TokenAssetGroupViewHolder(parent.inflateChild(R.layout.item_token_asset_group), imageLoader, itemHandler) TYPE_TOKEN_ASSET -> TokenAssetViewHolder(parent.inflateChild(R.layout.item_token_asset), imageLoader) else -> error("Unknown view type") } @@ -63,7 +64,7 @@ class BalanceListAdapter( return when (holder) { is NetworkAssetGroupViewHolder -> holder.bind(getItem(position) as NetworkGroupUi) is NetworkAssetViewHolder -> holder.bind(getItem(position) as NetworkAssetUi, itemHandler) - is TokenAssetGroupViewHolder -> holder.bind(getItem(position) as TokenGroupUi, itemHandler) + is TokenAssetGroupViewHolder -> holder.bind(getItem(position) as TokenGroupUi) is TokenAssetViewHolder -> holder.bind(getItem(position) as TokenAssetUi, itemHandler) else -> error("Unknown holder") } @@ -98,6 +99,7 @@ class BalanceListAdapter( tokenGroupPriceRateExtractor -> holder.bindPriceRate(item) tokenGroupRecentChangeExtractor -> holder.bindRecentChange(item) tokenGroupAmountExtractor -> holder.bindTotal(item) + tokenGroupTypeExtractor -> holder.bindGroupType(item) } } } @@ -158,5 +160,6 @@ private object TokenAssetPayloadGenerator : PayloadGenerator( private object TokenGroupAssetPayloadGenerator : PayloadGenerator( tokenGroupPriceRateExtractor, tokenGroupRecentChangeExtractor, - tokenGroupAmountExtractor + tokenGroupAmountExtractor, + tokenGroupTypeExtractor ) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt index 02e6a972e6..06a6872b1c 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/holders/TokenAssetGroupViewHolder.kt @@ -19,38 +19,66 @@ import kotlinx.android.synthetic.main.item_token_asset_group.view.itemTokenGroup class TokenAssetGroupViewHolder( containerView: View, private val imageLoader: ImageLoader, + private val itemHandler: BalanceListAdapter.ItemAssetHandler, ) : GroupedListHolder(containerView), ExpandableParentViewHolder { override var expandableItem: ExpandableParentItem? = null - fun bind(tokenGroup: TokenGroupUi, itemHandler: BalanceListAdapter.ItemAssetHandler) = with(containerView) { + fun bind(tokenGroup: TokenGroupUi) = with(containerView) { expandableItem = tokenGroup itemTokenGroupAssetImage.setTokenIcon(tokenGroup.tokenIcon, imageLoader) - bindPriceRate(tokenGroup) + bindPriceRateInternal(tokenGroup) - bindRecentChange(tokenGroup) + bindRecentChangeInternal(tokenGroup) - bindTotal(tokenGroup) + bindTotalInternal(tokenGroup) - itemAssetTokenGroupToken.text = tokenGroup.tokenSymbol + updateListener(tokenGroup) - setOnClickListener { itemHandler.tokenGroupClicked(tokenGroup) } + itemAssetTokenGroupToken.text = tokenGroup.tokenSymbol } fun bindTotal(networkAsset: TokenGroupUi) { + updateListener(networkAsset) + bindTotalInternal(networkAsset) + } + + fun bindRecentChange(networkAsset: TokenGroupUi) { + updateListener(networkAsset) + bindRecentChangeInternal(networkAsset) + } + + fun bindPriceRate(networkAsset: TokenGroupUi) { + updateListener(networkAsset) + bindPriceRateInternal(networkAsset) + } + + fun bindGroupType(networkAsset: TokenGroupUi) { + updateListener(networkAsset) + } + + private fun bindTotalInternal(networkAsset: TokenGroupUi) { val balance = networkAsset.balance containerView.itemAssetTokenGroupBalance.text = balance.token containerView.itemAssetTokenGroupPriceAmount.text = balance.fiat } - fun bindRecentChange(networkAsset: TokenGroupUi) = with(containerView) { - itemAssetTokenGroupRateChange.setTextColorRes(networkAsset.rateChangeColorRes) - itemAssetTokenGroupRateChange.text = networkAsset.recentRateChange + private fun bindRecentChangeInternal(networkAsset: TokenGroupUi) { + with(containerView) { + itemAssetTokenGroupRateChange.setTextColorRes(networkAsset.rateChangeColorRes) + itemAssetTokenGroupRateChange.text = networkAsset.recentRateChange + } + } + + private fun bindPriceRateInternal(networkAsset: TokenGroupUi) { + with(containerView) { + itemAssetTokenGroupRate.text = networkAsset.rate + } } - fun bindPriceRate(networkAsset: TokenGroupUi) = with(containerView) { - itemAssetTokenGroupRate.text = networkAsset.rate + private fun updateListener(tokenGroupUi: TokenGroupUi) { + containerView.setOnClickListener { itemHandler.tokenGroupClicked(tokenGroupUi) } } } From da8df5d3538f68d01521119594f80db8eb3e65b5 Mon Sep 17 00:00:00 2001 From: leohar Date: Mon, 11 Nov 2024 12:22:36 +0000 Subject: [PATCH 70/78] add portfolio localisation --- common/src/main/res/values-es/strings.xml | 1 + common/src/main/res/values-fr-rFR/strings.xml | 1 + common/src/main/res/values-in/strings.xml | 1 + common/src/main/res/values-it/strings.xml | 1 + common/src/main/res/values-ja/strings.xml | 1 + common/src/main/res/values-ko/strings.xml | 1 + common/src/main/res/values-pl/strings.xml | 1 + common/src/main/res/values-pt/strings.xml | 1 + common/src/main/res/values-ru/strings.xml | 1 + common/src/main/res/values-tr/strings.xml | 1 + common/src/main/res/values-vi/strings.xml | 1 + common/src/main/res/values-zh-rCN/strings.xml | 1 + 12 files changed, 12 insertions(+) diff --git a/common/src/main/res/values-es/strings.xml b/common/src/main/res/values-es/strings.xml index 2d5c85e18f..92e21215cb 100644 --- a/common/src/main/res/values-es/strings.xml +++ b/common/src/main/res/values-es/strings.xml @@ -1132,6 +1132,7 @@ Pistas no disponibles Nova necesita que la ubicación esté habilitada para poder realizar el escaneo bluetooth y encontrar tu dispositivo Ledger Por favor, habilita la geolocalización en las configuraciones del dispositivo + Seleccionar red Seleccione pistas para %d de %d Dirección o w3n diff --git a/common/src/main/res/values-fr-rFR/strings.xml b/common/src/main/res/values-fr-rFR/strings.xml index 1093eadfca..1a2d369044 100644 --- a/common/src/main/res/values-fr-rFR/strings.xml +++ b/common/src/main/res/values-fr-rFR/strings.xml @@ -1132,6 +1132,7 @@ Chemins non disponibles Nova a besoin que la localisation soit activée pour pouvoir effectuer un balayage Bluetooth afin de trouver votre appareil Ledger Veuillez activer la géolocalisation dans les paramètres de l\'appareil + Sélectionner un réseau Sélectionner des pistes pour %d sur %d Adresse ou w3n diff --git a/common/src/main/res/values-in/strings.xml b/common/src/main/res/values-in/strings.xml index e66f9d5448..d6b692fefb 100644 --- a/common/src/main/res/values-in/strings.xml +++ b/common/src/main/res/values-in/strings.xml @@ -1124,6 +1124,7 @@ Unavailable tracks Nova needs location to be enabled to be able to perform bluetooth scanning to find your Ledger device Please enable geo-location in device settings + Pilih jaringan Select tracks for %d of %d Address or w3n diff --git a/common/src/main/res/values-it/strings.xml b/common/src/main/res/values-it/strings.xml index eda74cbb6b..7ccfbe525a 100644 --- a/common/src/main/res/values-it/strings.xml +++ b/common/src/main/res/values-it/strings.xml @@ -1132,6 +1132,7 @@ Tracce non disponibili Nova ha bisogno che la posizione sia attivata per poter effettuare la scansione Bluetooth per trovare il tuo dispositivo Ledger Si prega di abilitare la geolocalizzazione nelle impostazioni del dispositivo + Seleziona rete Seleziona brani per %d di %d Indirizzo o w3n diff --git a/common/src/main/res/values-ja/strings.xml b/common/src/main/res/values-ja/strings.xml index cf8ebfb504..2b31a4ecfd 100644 --- a/common/src/main/res/values-ja/strings.xml +++ b/common/src/main/res/values-ja/strings.xml @@ -1124,6 +1124,7 @@ 利用不可のトラック Novaは、Ledgerデバイスを見つけるためにBluetoothスキャンを実行するために位置情報の有効化が必要です デバイス設定で位置情報を有効にしてください + ネットワークを選択 トラックを選択 %d / %d アドレスまたはw3n diff --git a/common/src/main/res/values-ko/strings.xml b/common/src/main/res/values-ko/strings.xml index 7334561d41..17b029a572 100644 --- a/common/src/main/res/values-ko/strings.xml +++ b/common/src/main/res/values-ko/strings.xml @@ -1124,6 +1124,7 @@ 사용할 수 없는 트랙 Ledger 장치를 찾기 위해 블루투스 스캔을 수행하려면 Nova는 위치 기능을 활성화해야 합니다. 기기 설정에서 지리적 위치를 활성화해주세요. + 네트워크 선택 트랙 선택 %d 중 %d 주소 또는 w3n diff --git a/common/src/main/res/values-pl/strings.xml b/common/src/main/res/values-pl/strings.xml index 4d9c03490d..0721f8cab6 100644 --- a/common/src/main/res/values-pl/strings.xml +++ b/common/src/main/res/values-pl/strings.xml @@ -1148,6 +1148,7 @@ Niedostępne trasy Nova wymaga włączenia lokalizacji, aby móc przeprowadzać skanowanie Bluetooth w celu znalezienia urządzenia Ledger Proszę włączyć geolokalizację w ustawieniach urządzenia + Wybierz sieć Wybierz trasy dla %d z %d Adres lub w3n diff --git a/common/src/main/res/values-pt/strings.xml b/common/src/main/res/values-pt/strings.xml index e86459e34e..a6aab8484e 100644 --- a/common/src/main/res/values-pt/strings.xml +++ b/common/src/main/res/values-pt/strings.xml @@ -1132,6 +1132,7 @@ Faixas indisponíveis Nova precisa que a localização seja ativada para poder realizar a varredura Bluetooth para encontrar seu dispositivo Ledger Por favor, ative a localização geográfica nas configurações do dispositivo + Selecionar rede Selecione faixas para %d de %d Endereço ou w3n diff --git a/common/src/main/res/values-ru/strings.xml b/common/src/main/res/values-ru/strings.xml index b1f4666312..33dc180a91 100644 --- a/common/src/main/res/values-ru/strings.xml +++ b/common/src/main/res/values-ru/strings.xml @@ -1148,6 +1148,7 @@ Недоступные треки Nova нуждается в включении местоположения, чтобы иметь возможность выполнять сканирование Bluetooth для поиска вашего устройства Ledger Пожалуйста, включите геолокацию в настройках устройства + Выберите сеть Выберите треки для %d из %d Адрес или w3n diff --git a/common/src/main/res/values-tr/strings.xml b/common/src/main/res/values-tr/strings.xml index 919eab0a59..1775904096 100644 --- a/common/src/main/res/values-tr/strings.xml +++ b/common/src/main/res/values-tr/strings.xml @@ -1132,6 +1132,7 @@ Ulaşılamayan yollar Nova\'nın Bluetooth taraması yaparak Ledger cihazınızı bulabilmesi için konumun etkinleştirilmesi gerekiyor Lütfen cihaz ayarlarında coğrafi konumu etkinleştirin + Ağ seç İçin şarkıları seçin %d / %d Adres veya w3n diff --git a/common/src/main/res/values-vi/strings.xml b/common/src/main/res/values-vi/strings.xml index 50cb3a328b..7379a43bef 100644 --- a/common/src/main/res/values-vi/strings.xml +++ b/common/src/main/res/values-vi/strings.xml @@ -1124,6 +1124,7 @@ Track không có sẵn Nova cần bật định vị để có thể thực hiện quét Bluetooth để tìm thiết bị Ledger của bạn Vui lòng bật định vị địa lý trong cài đặt thiết bị + Chọn mạng Chọn track cho %d trong %d Địa chỉ hoặc w3n diff --git a/common/src/main/res/values-zh-rCN/strings.xml b/common/src/main/res/values-zh-rCN/strings.xml index dc2ebea500..8e720b42a4 100644 --- a/common/src/main/res/values-zh-rCN/strings.xml +++ b/common/src/main/res/values-zh-rCN/strings.xml @@ -1124,6 +1124,7 @@ 不可用的轨道 Nova需要启用地理位置,以便能够进行蓝牙扫描查找您的Ledger设备 请在设备设置中启用地理位置 + 选择网络 选择曲目 %d / %d 地址或w3n From 02ca351f2900429dcfbc19f876626774bad8ee9c Mon Sep 17 00:00:00 2001 From: valentun Date: Mon, 11 Nov 2024 13:32:59 +0100 Subject: [PATCH 71/78] Optimizations --- .../nova/common/utils/FlowExt.kt | 2 ++ .../formatting/DynamicPrecisionFormatter.kt | 10 ++++++- .../formatting/FixedPrecisionFormatter.kt | 6 +++- .../utils/formatting/NumberFormatters.kt | 3 +- .../balance/common/ExpandableAssetsMixin.kt | 30 +++++++++++-------- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/FlowExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/FlowExt.kt index e5a94291af..06686e8ced 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/FlowExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/FlowExt.kt @@ -145,6 +145,8 @@ inline fun withFlowScope(crossinline block: suspend (scope: CoroutineScope) fun combineToPair(flow1: Flow, flow2: Flow): Flow> = combine(flow1, flow2, ::Pair) +fun combineToTriple(flow1: Flow, flow2: Flow, flow3: Flow): Flow> = combine(flow1, flow2, flow3, ::Triple) + /** * Modifies flow so that it firstly emits [LoadingState.Loading] state for each element from upstream. * Then, it constructs new source via [sourceSupplier] and emits all of its items wrapped into [LoadingState.Loaded] state diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/formatting/DynamicPrecisionFormatter.kt b/common/src/main/java/io/novafoundation/nova/common/utils/formatting/DynamicPrecisionFormatter.kt index b5f2554719..5cfb1a8c47 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/formatting/DynamicPrecisionFormatter.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/formatting/DynamicPrecisionFormatter.kt @@ -3,6 +3,7 @@ package io.novafoundation.nova.common.utils.formatting import java.lang.Integer.max import java.math.BigDecimal import java.math.RoundingMode +import java.text.DecimalFormat import kotlin.math.min class DynamicPrecisionFormatter( @@ -10,6 +11,8 @@ class DynamicPrecisionFormatter( private val minPrecision: Int, ) : NumberFormatter { + private val patternCache = mutableMapOf() + override fun format(number: BigDecimal, roundingMode: RoundingMode): String { // scale() - total amount of digits after 0., // precision() - amount of non-zero digits in decimal part @@ -18,6 +21,11 @@ class DynamicPrecisionFormatter( val formattingPrecision = max(minScale, requiredPrecision) - return decimalFormatterFor(patternWith(formattingPrecision), roundingMode).format(number) + val formatter = patternCache.getOrPut(formattingPrecision) { decimalFormatterFor(patternWith(formattingPrecision)) } + if (formatter.roundingMode != roundingMode) { + formatter.roundingMode = roundingMode + } + + return formatter.format(number) } } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/formatting/FixedPrecisionFormatter.kt b/common/src/main/java/io/novafoundation/nova/common/utils/formatting/FixedPrecisionFormatter.kt index 361e7e2afc..c03638b908 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/formatting/FixedPrecisionFormatter.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/formatting/FixedPrecisionFormatter.kt @@ -5,8 +5,12 @@ import java.math.RoundingMode class FixedPrecisionFormatter(private val precision: Int) : NumberFormatter { + private val delegate = decimalFormatterFor(patternWith(precision)) + override fun format(number: BigDecimal, roundingMode: RoundingMode): String { - val delegate = decimalFormatterFor(patternWith(precision), roundingMode) + if (delegate.roundingMode != roundingMode) { + delegate.roundingMode = roundingMode + } return delegate.format(number) } diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/formatting/NumberFormatters.kt b/common/src/main/java/io/novafoundation/nova/common/utils/formatting/NumberFormatters.kt index 47970dedea..1c58aa033f 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/formatting/NumberFormatters.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/formatting/NumberFormatters.kt @@ -169,7 +169,7 @@ fun formatDateISO_8601_NoMs(date: Date): String { return dateTimeFormatISO_8601_NoMs.format(date) } -fun decimalFormatterFor(pattern: String, roundingMode: RoundingMode): DecimalFormat { +fun decimalFormatterFor(pattern: String): DecimalFormat { return DecimalFormat(pattern).apply { val symbols = decimalFormatSymbols @@ -178,7 +178,6 @@ fun decimalFormatterFor(pattern: String, roundingMode: RoundingMode): DecimalFor decimalFormatSymbols = symbols - this.roundingMode = roundingMode decimalFormatSymbols = decimalFormatSymbols } } diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt index 074d29bd6b..2eea4d43d6 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -3,6 +3,9 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common import io.novafoundation.nova.common.data.model.switch import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.presentation.AssetIconProvider +import io.novafoundation.nova.common.utils.combineToTriple +import io.novafoundation.nova.common.utils.measureExecution +import io.novafoundation.nova.common.utils.throttleLast import io.novafoundation.nova.common.utils.toggle import io.novafoundation.nova.common.utils.updateValue import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult @@ -14,8 +17,9 @@ import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.mapLatest +import kotlin.time.Duration.Companion.milliseconds class ExpandableAssetsMixinFactory( private val assetIconProvider: AssetIconProvider, @@ -50,20 +54,22 @@ class RealExpandableAssetsMixin( private val expandedTokenIdsFlow = MutableStateFlow(setOf()) - override val assetModelsFlow: Flow> = combine( + override val assetModelsFlow: Flow> = combineToTriple( assetsFlow, expandedTokenIdsFlow, selectedCurrency - ) { assetesByViewMode, expandedTokens, currency -> - when (assetesByViewMode) { - is AssetsByViewModeResult.ByNetworks -> assetesByViewMode.assets.mapGroupedAssetsToUi(amountFormatter, assetIconProvider, currency) - is AssetsByViewModeResult.ByTokens -> assetesByViewMode.tokens.mapGroupedAssetsToUi( - amountFormatter = amountFormatter, - assetIconProvider = assetIconProvider, - assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } - ) - } - }.distinctUntilChanged() + ) + .throttleLast(500.milliseconds) + .mapLatest { (assetsByViewMode, expandedTokens, currency) -> + when (assetsByViewMode) { + is AssetsByViewModeResult.ByNetworks -> assetsByViewMode.assets.mapGroupedAssetsToUi(amountFormatter, assetIconProvider, currency) + is AssetsByViewModeResult.ByTokens -> assetsByViewMode.tokens.mapGroupedAssetsToUi( + amountFormatter = amountFormatter, + assetIconProvider = assetIconProvider, + assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } + ) + } + }.distinctUntilChanged() override fun expandToken(tokenGroupUi: TokenGroupUi) { expandedTokenIdsFlow.updateValue { it.toggle(tokenGroupUi.itemId) } From 3349daf8dcacebbf0b9f12705a97ff7f42c4cb62 Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Mon, 11 Nov 2024 13:52:57 +0100 Subject: [PATCH 72/78] Run ktlint --- .../presentation/balance/common/ExpandableAssetsMixin.kt | 4 ---- .../presentation/balance/list/BalanceListFragment.kt | 1 - .../presentation/balance/list/BalanceListViewModel.kt | 1 - .../presentation/balance/search/AssetSearchFragment.kt | 1 - .../presentation/balance/search/AssetSearchViewModel.kt | 1 - .../presentation/buy/flow/asset/AssetBuyFlowViewModel.kt | 1 - .../presentation/flow/asset/AssetFlowFragment.kt | 1 - .../presentation/flow/asset/AssetFlowViewModel.kt | 1 - .../receive/flow/asset/AssetReceiveFlowViewModel.kt | 1 - .../presentation/send/flow/asset/AssetSendFlowViewModel.kt | 1 - .../feature_wallet_api/presentation/model/AmountModel.kt | 6 +++--- 11 files changed, 3 insertions(+), 16 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt index 2eea4d43d6..783561b8a9 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -4,8 +4,6 @@ import io.novafoundation.nova.common.data.model.switch import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.utils.combineToTriple -import io.novafoundation.nova.common.utils.measureExecution -import io.novafoundation.nova.common.utils.throttleLast import io.novafoundation.nova.common.utils.toggle import io.novafoundation.nova.common.utils.updateValue import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult @@ -19,7 +17,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.mapLatest -import kotlin.time.Duration.Companion.milliseconds class ExpandableAssetsMixinFactory( private val assetIconProvider: AssetIconProvider, @@ -59,7 +56,6 @@ class RealExpandableAssetsMixin( expandedTokenIdsFlow, selectedCurrency ) - .throttleLast(500.milliseconds) .mapLatest { (assetsByViewMode, expandedTokens, currency) -> when (assetsByViewMode) { is AssetsByViewModeResult.ByNetworks -> assetsByViewMode.assets.mapGroupedAssetsToUi(amountFormatter, assetIconProvider, currency) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt index b7fec4ee90..90c9211b52 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt @@ -24,7 +24,6 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDec import io.novafoundation.nova.feature_assets.presentation.balance.common.createForAssets import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetsHeaderAdapter -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_wallet_api.domain.model.Asset import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.android.synthetic.main.fragment_balance_list.balanceListAssets diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt index 824dbf2f90..59265f0fdb 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt @@ -28,7 +28,6 @@ import io.novafoundation.nova.feature_wallet_api.presentation.model.formatBalanc import io.novafoundation.nova.feature_assets.presentation.balance.list.model.NftPreviewUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.TotalBalanceModel import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetViewModeModel -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt index a4fdee087e..fd29d8aa92 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchFragment.kt @@ -26,7 +26,6 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.Balance import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.applyDefaultTo import io.novafoundation.nova.feature_assets.presentation.balance.common.createForAssets import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.android.synthetic.main.fragment_asset_search.searchAssetContainer import kotlinx.android.synthetic.main.fragment_asset_search.searchAssetList diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt index b93036183c..1fcac9279e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/search/AssetSearchViewModel.kt @@ -6,7 +6,6 @@ import io.novafoundation.nova.feature_assets.domain.assets.search.AssetSearchInt import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload import io.novafoundation.nova.feature_assets.presentation.AssetsRouter import io.novafoundation.nova.feature_assets.presentation.balance.common.ExpandableAssetsMixinFactory -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.coroutines.flow.MutableStateFlow diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt index 3bd587c92f..42ee15147f 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/buy/flow/asset/AssetBuyFlowViewModel.kt @@ -12,7 +12,6 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.Control import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowViewModel import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_buy_api.presentation.mixin.BuyMixin import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt index e18be62fce..42d1891ca4 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowFragment.kt @@ -24,7 +24,6 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDec import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.TokenAssetGroupDecorationPreferences import io.novafoundation.nova.feature_assets.presentation.balance.common.baseDecoration.applyDefaultTo import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.receive.view.LedgerNotSupportedWarningBottomSheet import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import javax.inject.Inject diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt index 45bbc983df..e651ae3206 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/flow/asset/AssetFlowViewModel.kt @@ -24,7 +24,6 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers import io.novafoundation.nova.feature_assets.presentation.balance.common.mappers.mapGroupedAssetsToUi import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.BalanceListRvItem import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt index f829267d69..761aa0d94d 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/receive/flow/asset/AssetReceiveFlowViewModel.kt @@ -13,7 +13,6 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.Control import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowViewModel import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_wallet_api.presentation.model.AmountFormatter import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt index d213342536..135a2126af 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/send/flow/asset/AssetSendFlowViewModel.kt @@ -22,7 +22,6 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.model.ite import io.novafoundation.nova.feature_assets.presentation.balance.list.model.items.TokenGroupUi import io.novafoundation.nova.feature_assets.presentation.flow.asset.AssetFlowViewModel import io.novafoundation.nova.feature_assets.presentation.flow.network.NetworkFlowPayload -import io.novafoundation.nova.feature_assets.presentation.model.AssetModel import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor import io.novafoundation.nova.feature_currency_api.domain.model.Currency diff --git a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt index ec3e64b021..3bfadfdbc9 100644 --- a/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt +++ b/feature-wallet-api/src/main/java/io/novafoundation/nova/feature_wallet_api/presentation/model/AmountModel.kt @@ -18,9 +18,9 @@ data class AmountModel( // Override it since SpannableString is not equals by content override fun equals(other: Any?): Boolean { - return other is AmountModel - && other.token.toString() == token.toString() - && other.fiat?.toString() == fiat?.toString() + return other is AmountModel && + other.token.toString() == token.toString() && + other.fiat?.toString() == fiat?.toString() } } From 173ee1f0cfb14f3cc31eae89be1335d14dc318fc Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Mon, 11 Nov 2024 13:57:26 +0100 Subject: [PATCH 73/78] Clean code --- .../presentation/balance/list/model/items/TokenAssetUi.kt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt index e2a4b59793..3c179a103e 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/items/TokenAssetUi.kt @@ -14,12 +14,4 @@ data class TokenAssetUi( ) : AssetRvItem, ExpandableChildItem { override val itemId: String = "token_" + asset.token.configuration.fullId.toString() - - override fun equals(other: Any?): Boolean { - if (other is TokenAssetUi) { - return chain.id == other.chain.id - } - - return false - } } From e8e7f243cf5bdd68f52d25391277c5ac05d1bcae Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Mon, 11 Nov 2024 14:40:14 +0100 Subject: [PATCH 74/78] Add throttling to asset list --- .../presentation/balance/common/ExpandableAssetsMixin.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt index 783561b8a9..ba2651cf32 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -4,6 +4,7 @@ import io.novafoundation.nova.common.data.model.switch import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.utils.combineToTriple +import io.novafoundation.nova.common.utils.throttleLast import io.novafoundation.nova.common.utils.toggle import io.novafoundation.nova.common.utils.updateValue import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult @@ -17,6 +18,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.mapLatest +import kotlin.time.Duration.Companion.milliseconds class ExpandableAssetsMixinFactory( private val assetIconProvider: AssetIconProvider, @@ -65,7 +67,8 @@ class RealExpandableAssetsMixin( assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } ) } - }.distinctUntilChanged() + }.throttleLast(300.milliseconds) + .distinctUntilChanged() override fun expandToken(tokenGroupUi: TokenGroupUi) { expandedTokenIdsFlow.updateValue { it.toggle(tokenGroupUi.itemId) } From ed0a94f150a5ffd13a431946b76ee8554fc5f6ed Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Mon, 11 Nov 2024 14:44:30 +0100 Subject: [PATCH 75/78] Bump version code --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 470200fc98..927170fa5d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ buildscript { ext { // App version - versionName = '8.7.3' - versionCode = 157 + versionName = '9.0.0' + versionCode = 158 applicationId = "io.novafoundation.nova" releaseApplicationSuffix = "market" From c94da3640dab066687cb5873d9183ac017da9d9a Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Mon, 11 Nov 2024 14:49:28 +0100 Subject: [PATCH 76/78] Update ExpandableAssetsMixin.kt --- .../presentation/balance/common/ExpandableAssetsMixin.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt index ba2651cf32..d764d96a92 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -54,7 +54,7 @@ class RealExpandableAssetsMixin( private val expandedTokenIdsFlow = MutableStateFlow(setOf()) override val assetModelsFlow: Flow> = combineToTriple( - assetsFlow, + assetsFlow.throttleLast(300.milliseconds), expandedTokenIdsFlow, selectedCurrency ) @@ -67,7 +67,7 @@ class RealExpandableAssetsMixin( assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } ) } - }.throttleLast(300.milliseconds) + } .distinctUntilChanged() override fun expandToken(tokenGroupUi: TokenGroupUi) { From 23050ef3f2a5959184727d73224687cde666eb2a Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Mon, 11 Nov 2024 14:55:00 +0100 Subject: [PATCH 77/78] Fixed trhottling --- .../presentation/balance/common/AssetListMixin.kt | 11 ++++++++--- .../balance/common/ExpandableAssetsMixin.kt | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt index 4f247cc3d1..a7f40bbcb1 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/AssetListMixin.kt @@ -1,7 +1,9 @@ package io.novafoundation.nova.feature_assets.presentation.balance.common import io.novafoundation.nova.common.data.model.AssetViewMode +import io.novafoundation.nova.common.utils.combineToPair import io.novafoundation.nova.common.utils.shareInBackground +import io.novafoundation.nova.common.utils.throttleLast import io.novafoundation.nova.feature_assets.domain.WalletInteractor import io.novafoundation.nova.feature_assets.domain.assets.ExternalBalancesInteractor import io.novafoundation.nova.feature_assets.domain.assets.list.AssetsListInteractor @@ -15,6 +17,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.combine +import kotlin.time.Duration.Companion.milliseconds class AssetListMixinFactory( private val walletInteractor: WalletInteractor, @@ -67,11 +70,13 @@ class RealAssetListMixin( override val assetsViewModeFlow = assetsListInteractor.assetsViewModeFlow() .shareInBackground() + private val throttledBalance = combineToPair(filteredAssetsFlow, externalBalancesFlow) + .throttleLast(300.milliseconds) + private val assetsByViewMode = combine( - filteredAssetsFlow, - externalBalancesFlow, + throttledBalance, assetsViewModeFlow - ) { assets, externalBalances, viewMode -> + ) { (assets, externalBalances), viewMode -> when (viewMode) { AssetViewMode.NETWORKS -> walletInteractor.groupAssetsByNetwork(assets, externalBalances).byNetworks() AssetViewMode.TOKENS -> walletInteractor.groupAssetsByToken(assets, externalBalances).byTokens() diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt index d764d96a92..2286780f55 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -54,7 +54,7 @@ class RealExpandableAssetsMixin( private val expandedTokenIdsFlow = MutableStateFlow(setOf()) override val assetModelsFlow: Flow> = combineToTriple( - assetsFlow.throttleLast(300.milliseconds), + assetsFlow, expandedTokenIdsFlow, selectedCurrency ) From ae932756a966cb34335990baa0fa3c1420a7eb9f Mon Sep 17 00:00:00 2001 From: antonijzelinskij Date: Mon, 11 Nov 2024 15:55:06 +0100 Subject: [PATCH 78/78] Fixed groupping issue --- .../domain/common/TokenAssetSorting.kt | 28 ++++++++++++++----- .../balance/common/ExpandableAssetsMixin.kt | 21 ++++++-------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt index eb3241bee4..0a976a3580 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/domain/common/TokenAssetSorting.kt @@ -46,9 +46,9 @@ fun groupAndSortAssetsByToken( .map { asset -> AssetWithNetwork(chainsById.getValue(asset.token.configuration.chainId), asset, asset.totalWithOffChain(externalBalances)) } .groupBy { mapToTokenGroup(it) } .mapValues { (_, assets) -> assets.sortedWith(assetComparator) } - .mapKeys { (token, assets) -> + .mapKeys { (tokenWrapper, assets) -> TokenAssetGroup( - token = token, + token = tokenWrapper.token, groupBalance = assets.fold(AssetBalance.ZERO) { acc, element -> acc + element.balanceWithOffChain }, itemsCount = assets.size ) @@ -72,9 +72,23 @@ fun getTokenAssetGroupBaseComparator( .then(TokenSymbol.defaultComparatorFrom { it.token.symbol }) } -private fun mapToTokenGroup(it: AssetWithNetwork) = TokenAssetGroup.Token( - it.asset.token.configuration.icon, - it.asset.token.configuration.symbol.normalize(), - it.asset.token.currency, - it.asset.token.coinRate +private fun mapToTokenGroup(it: AssetWithNetwork) = TokenGroupWrapper( + TokenAssetGroup.Token( + it.asset.token.configuration.icon, + it.asset.token.configuration.symbol.normalize(), + it.asset.token.currency, + it.asset.token.coinRate + ) ) + +// Helper class to group items by symbol only +private class TokenGroupWrapper(val token: TokenAssetGroup.Token) { + + override fun equals(other: Any?): Boolean { + return other is TokenGroupWrapper && token.symbol == other.token.symbol + } + + override fun hashCode(): Int { + return token.symbol.hashCode() + } +} diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt index 2286780f55..71f74fc753 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/common/ExpandableAssetsMixin.kt @@ -4,7 +4,6 @@ import io.novafoundation.nova.common.data.model.switch import io.novafoundation.nova.common.data.repository.AssetsViewModeRepository import io.novafoundation.nova.common.presentation.AssetIconProvider import io.novafoundation.nova.common.utils.combineToTriple -import io.novafoundation.nova.common.utils.throttleLast import io.novafoundation.nova.common.utils.toggle import io.novafoundation.nova.common.utils.updateValue import io.novafoundation.nova.feature_assets.domain.assets.models.AssetsByViewModeResult @@ -18,7 +17,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.mapLatest -import kotlin.time.Duration.Companion.milliseconds class ExpandableAssetsMixinFactory( private val assetIconProvider: AssetIconProvider, @@ -57,17 +55,16 @@ class RealExpandableAssetsMixin( assetsFlow, expandedTokenIdsFlow, selectedCurrency - ) - .mapLatest { (assetsByViewMode, expandedTokens, currency) -> - when (assetsByViewMode) { - is AssetsByViewModeResult.ByNetworks -> assetsByViewMode.assets.mapGroupedAssetsToUi(amountFormatter, assetIconProvider, currency) - is AssetsByViewModeResult.ByTokens -> assetsByViewMode.tokens.mapGroupedAssetsToUi( - amountFormatter = amountFormatter, - assetIconProvider = assetIconProvider, - assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } - ) - } + ).mapLatest { (assetsByViewMode, expandedTokens, currency) -> + when (assetsByViewMode) { + is AssetsByViewModeResult.ByNetworks -> assetsByViewMode.assets.mapGroupedAssetsToUi(amountFormatter, assetIconProvider, currency) + is AssetsByViewModeResult.ByTokens -> assetsByViewMode.tokens.mapGroupedAssetsToUi( + amountFormatter = amountFormatter, + assetIconProvider = assetIconProvider, + assetFilter = { groupId, assetsInGroup -> filterTokens(groupId, assetsInGroup, expandedTokens) } + ) } + } .distinctUntilChanged() override fun expandToken(tokenGroupUi: TokenGroupUi) {