Updated on 2026-08-14
This commit is contained in:
parent
add9d552b4
commit
e7ebbb931e
12 changed files with 516 additions and 76 deletions
|
|
@ -24,6 +24,7 @@ import com.tangem.datasource.local.walletconnect.WalletConnectStore
|
||||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||||
import com.tangem.domain.account.supplier.MultiAccountListSupplier
|
import com.tangem.domain.account.supplier.MultiAccountListSupplier
|
||||||
|
import com.tangem.domain.account.supplier.SingleAccountSupplier
|
||||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
||||||
import com.tangem.domain.walletconnect.WcPairService
|
import com.tangem.domain.walletconnect.WcPairService
|
||||||
import com.tangem.domain.walletconnect.WcRequestService
|
import com.tangem.domain.walletconnect.WcRequestService
|
||||||
|
|
@ -185,11 +186,13 @@ internal object WalletConnectDataModule {
|
||||||
walletManagersFacade: WalletManagersFacade,
|
walletManagersFacade: WalletManagersFacade,
|
||||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
||||||
|
singleAccountSupplier: SingleAccountSupplier,
|
||||||
): WcNetworksConverter = WcNetworksConverter(
|
): WcNetworksConverter = WcNetworksConverter(
|
||||||
namespaceConverters = namespaceConverters,
|
namespaceConverters = namespaceConverters,
|
||||||
walletManagersFacade = walletManagersFacade,
|
walletManagersFacade = walletManagersFacade,
|
||||||
singleAccountStatusListSupplier = singleAccountStatusListSupplier,
|
singleAccountStatusListSupplier = singleAccountStatusListSupplier,
|
||||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||||
|
singleAccountSupplier = singleAccountSupplier,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.data.walletconnect.utils.*
|
import com.tangem.data.walletconnect.utils.*
|
||||||
import com.tangem.datasource.local.walletconnect.WalletConnectStore
|
import com.tangem.datasource.local.walletconnect.WalletConnectStore
|
||||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||||
|
import com.tangem.domain.models.account.AccountId
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.walletconnect.WcAnalyticEvents
|
import com.tangem.domain.walletconnect.WcAnalyticEvents
|
||||||
import com.tangem.domain.walletconnect.model.WcSession
|
import com.tangem.domain.walletconnect.model.WcSession
|
||||||
|
|
@ -37,12 +38,15 @@ internal class DefaultWcSessionsManager(
|
||||||
) : WcSessionsManager, WcSdkObserver {
|
) : WcSessionsManager, WcSdkObserver {
|
||||||
|
|
||||||
private val onSessionDelete = Channel<Wallet.Model.SessionDelete>(capacity = Channel.BUFFERED)
|
private val onSessionDelete = Channel<Wallet.Model.SessionDelete>(capacity = Channel.BUFFERED)
|
||||||
|
private val oneTimeMigration = MutableStateFlow(false)
|
||||||
|
|
||||||
override val sessions: Flow<Map<UserWallet, List<WcSession>>>
|
override val sessions: Flow<Map<UserWallet, List<WcSession>>>
|
||||||
get() = combine(getWallets(), store.sessions) { wallets, inStore -> wallets to inStore }
|
get() = combine(getWallets(), store.sessions) { wallets, inStore -> wallets to inStore }
|
||||||
.transform { pair ->
|
.transform { pair ->
|
||||||
val (wallets, inStore) = pair
|
val (wallets, inStore) = pair
|
||||||
val inSdk: List<Wallet.Model.Session> = WalletKit.getListOfActiveSessions()
|
val inSdk: List<Wallet.Model.Session> = WalletKit.getListOfActiveSessions()
|
||||||
|
val someMigrate = migrateToAccountSession(inStore)
|
||||||
|
if (someMigrate) return@transform
|
||||||
val associatedSessions: List<WcSession> = associate(inSdk, inStore, wallets)
|
val associatedSessions: List<WcSession> = associate(inSdk, inStore, wallets)
|
||||||
val someRemove = removeUnknownSessions(inStore, inSdk, associatedSessions)
|
val someRemove = removeUnknownSessions(inStore, inSdk, associatedSessions)
|
||||||
if (someRemove) return@transform // ignore emit, wait next one
|
if (someRemove) return@transform // ignore emit, wait next one
|
||||||
|
|
@ -51,6 +55,26 @@ internal class DefaultWcSessionsManager(
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.flowOn(dispatchers.io)
|
.flowOn(dispatchers.io)
|
||||||
|
|
||||||
|
private suspend fun migrateToAccountSession(inStore: Set<WcSessionDTO>): Boolean {
|
||||||
|
if (!accountsFeatureToggles.isFeatureEnabled) return false
|
||||||
|
if (oneTimeMigration.value) return false
|
||||||
|
|
||||||
|
var someMigrated = false
|
||||||
|
|
||||||
|
val updatedSessions = inStore.mapTo(mutableSetOf()) { sessionDTO ->
|
||||||
|
if (sessionDTO.accountId == null) {
|
||||||
|
someMigrated = true
|
||||||
|
val mainAccountId = AccountId.forMainCryptoPortfolio(sessionDTO.walletId)
|
||||||
|
sessionDTO.copy(accountId = mainAccountId)
|
||||||
|
} else {
|
||||||
|
sessionDTO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (someMigrated) store.saveSessions(updatedSessions)
|
||||||
|
oneTimeMigration.value = true
|
||||||
|
return someMigrated
|
||||||
|
}
|
||||||
|
|
||||||
override fun onWcSdkInit() {
|
override fun onWcSdkInit() {
|
||||||
listenOnSessionDelete()
|
listenOnSessionDelete()
|
||||||
extendSessions()
|
extendSessions()
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@ package com.tangem.data.walletconnect.utils
|
||||||
import com.reown.walletkit.client.Wallet
|
import com.reown.walletkit.client.Wallet
|
||||||
import com.tangem.data.common.currency.isCustomCoin
|
import com.tangem.data.common.currency.isCustomCoin
|
||||||
import com.tangem.data.walletconnect.model.CAIP10
|
import com.tangem.data.walletconnect.model.CAIP10
|
||||||
|
import com.tangem.domain.account.producer.SingleAccountProducer
|
||||||
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
|
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
|
||||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||||
|
import com.tangem.domain.account.supplier.SingleAccountSupplier
|
||||||
import com.tangem.domain.models.account.Account
|
import com.tangem.domain.models.account.Account
|
||||||
import com.tangem.domain.models.account.AccountId
|
import com.tangem.domain.models.account.AccountId
|
||||||
import com.tangem.domain.models.account.AccountStatus
|
import com.tangem.domain.models.account.AccountStatus
|
||||||
|
|
@ -24,6 +26,7 @@ internal class WcNetworksConverter @Inject constructor(
|
||||||
private val namespaceConverters: Set<WcNamespaceConverter>,
|
private val namespaceConverters: Set<WcNamespaceConverter>,
|
||||||
private val walletManagersFacade: WalletManagersFacade,
|
private val walletManagersFacade: WalletManagersFacade,
|
||||||
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
||||||
|
private val singleAccountSupplier: SingleAccountSupplier,
|
||||||
private val multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
private val multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
@ -101,7 +104,7 @@ internal class WcNetworksConverter @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getAccount(accountId: AccountId): Account? {
|
suspend fun getAccount(accountId: AccountId): Account? {
|
||||||
return getAccountStatus(accountId)?.account
|
return singleAccountSupplier.getSyncOrNull(SingleAccountProducer.Params(accountId))
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun convertNetworksForApprove(sessionForApprove: WcSessionApprove): List<Network> {
|
suspend fun convertNetworksForApprove(sessionForApprove: WcSessionApprove): List<Network> {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.tangem.features.walletconnect.connections.entity
|
package com.tangem.features.walletconnect.connections.entity
|
||||||
|
|
||||||
|
import com.tangem.common.ui.account.AccountTitleUM
|
||||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
|
|
@ -10,7 +11,7 @@ data class WcConnectedAppInfoUM(
|
||||||
val verifiedDAppState: VerifiedDAppState,
|
val verifiedDAppState: VerifiedDAppState,
|
||||||
val notification: WcAppInfoSecurityNotification? = null,
|
val notification: WcAppInfoSecurityNotification? = null,
|
||||||
val appSubtitle: String,
|
val appSubtitle: String,
|
||||||
val walletName: String,
|
val portfolioName: AccountTitleUM?,
|
||||||
val connectingTime: Long?,
|
val connectingTime: Long?,
|
||||||
val networks: ImmutableList<WcNetworkInfoItem.Required>,
|
val networks: ImmutableList<WcNetworkInfoItem.Required>,
|
||||||
val disconnectButtonConfig: WcPrimaryButtonConfig,
|
val disconnectButtonConfig: WcPrimaryButtonConfig,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
package com.tangem.features.walletconnect.connections.entity
|
package com.tangem.features.walletconnect.connections.entity
|
||||||
|
|
||||||
|
import com.tangem.common.ui.account.AccountTitleUM
|
||||||
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
|
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
|
||||||
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
|
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
internal data class WcConnectionsState(
|
internal data class WcConnectionsState(
|
||||||
val topAppBarConfig: WcConnectionsTopAppBarConfig,
|
val topAppBarConfig: WcConnectionsTopAppBarConfig,
|
||||||
val connections: ImmutableList<WcConnectionsUM>,
|
val connections: WcConnections,
|
||||||
val onNewConnectionClick: () -> Unit,
|
val onNewConnectionClick: () -> Unit,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -15,6 +16,39 @@ internal data class WcConnectionsTopAppBarConfig(
|
||||||
val disconnectAllItem: TangemDropdownMenuItem,
|
val disconnectAllItem: TangemDropdownMenuItem,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal sealed interface WcConnections {
|
||||||
|
data object Loading : WcConnections
|
||||||
|
data class WalletMode(
|
||||||
|
val connections: ImmutableList<WcConnectionsUM>,
|
||||||
|
) : WcConnections
|
||||||
|
|
||||||
|
data class AccountMode(
|
||||||
|
val items: ImmutableList<WcConnectionsItem>,
|
||||||
|
) : WcConnections
|
||||||
|
|
||||||
|
fun isNotEmpty(): Boolean = when (this) {
|
||||||
|
is AccountMode -> items.isNotEmpty()
|
||||||
|
is WalletMode -> connections.isNotEmpty()
|
||||||
|
Loading -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed interface WcConnectionsItem {
|
||||||
|
val id: String
|
||||||
|
|
||||||
|
data class WalletHeader(
|
||||||
|
override val id: String,
|
||||||
|
val walletName: String,
|
||||||
|
val isLocked: Boolean,
|
||||||
|
) : WcConnectionsItem
|
||||||
|
|
||||||
|
data class PortfolioConnections(
|
||||||
|
override val id: String,
|
||||||
|
val portfolioTitle: AccountTitleUM,
|
||||||
|
val connectedApps: ImmutableList<WcConnectedAppInfo>,
|
||||||
|
) : WcConnectionsItem
|
||||||
|
}
|
||||||
|
|
||||||
internal data class WcConnectionsUM(
|
internal data class WcConnectionsUM(
|
||||||
val userWalletId: String,
|
val userWalletId: String,
|
||||||
val walletName: String,
|
val walletName: String,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import com.tangem.features.walletconnect.connections.entity.WcAppInfoSecurityNot
|
||||||
import com.tangem.features.walletconnect.connections.model.transformers.WcAppSubtitleConverter
|
import com.tangem.features.walletconnect.connections.model.transformers.WcAppSubtitleConverter
|
||||||
import com.tangem.features.walletconnect.connections.routes.ConnectedAppInfoRoutes
|
import com.tangem.features.walletconnect.connections.routes.ConnectedAppInfoRoutes
|
||||||
import com.tangem.features.walletconnect.impl.R
|
import com.tangem.features.walletconnect.impl.R
|
||||||
|
import com.tangem.features.walletconnect.transaction.converter.WcPortfolioNameDelegate
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
@ -39,10 +40,12 @@ internal class WcConnectedAppInfoModel @Inject constructor(
|
||||||
private val wcSessionsUseCase: WcSessionsUseCase,
|
private val wcSessionsUseCase: WcSessionsUseCase,
|
||||||
private val messageSender: UiMessageSender,
|
private val messageSender: UiMessageSender,
|
||||||
private val disconnectUseCase: WcDisconnectUseCase,
|
private val disconnectUseCase: WcDisconnectUseCase,
|
||||||
|
portfolioNameDelegateFactory: WcPortfolioNameDelegate.Factory,
|
||||||
override val dispatchers: CoroutineDispatcherProvider,
|
override val dispatchers: CoroutineDispatcherProvider,
|
||||||
paramsContainer: ParamsContainer,
|
paramsContainer: ParamsContainer,
|
||||||
) : Model() {
|
) : Model() {
|
||||||
|
|
||||||
|
private val portfolioNameDelegate = portfolioNameDelegateFactory.create(modelScope)
|
||||||
private val params = paramsContainer.require<WcConnectedAppInfoContainerComponent.Params>()
|
private val params = paramsContainer.require<WcConnectedAppInfoContainerComponent.Params>()
|
||||||
val uiState: StateFlow<WcConnectedAppInfoUM?>
|
val uiState: StateFlow<WcConnectedAppInfoUM?>
|
||||||
field = MutableStateFlow<WcConnectedAppInfoUM?>(null)
|
field = MutableStateFlow<WcConnectedAppInfoUM?>(null)
|
||||||
|
|
@ -68,7 +71,7 @@ internal class WcConnectedAppInfoModel @Inject constructor(
|
||||||
isVerified = session.securityStatus == CheckDAppResult.SAFE,
|
isVerified = session.securityStatus == CheckDAppResult.SAFE,
|
||||||
verifiedDAppState = extractVerifiedState(session),
|
verifiedDAppState = extractVerifiedState(session),
|
||||||
appSubtitle = WcAppSubtitleConverter.convert(session.sdkModel.appMetaData),
|
appSubtitle = WcAppSubtitleConverter.convert(session.sdkModel.appMetaData),
|
||||||
walletName = session.wallet.name,
|
portfolioName = portfolioNameDelegate.createAccountTitleUM(session),
|
||||||
connectingTime = session.connectingTime,
|
connectingTime = session.connectingTime,
|
||||||
networks = session.networks
|
networks = session.networks
|
||||||
.distinctBy { network -> network.rawId }
|
.distinctBy { network -> network.rawId }
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@ import com.tangem.core.ui.message.DialogMessage
|
||||||
import com.tangem.core.ui.message.EventMessageAction
|
import com.tangem.core.ui.message.EventMessageAction
|
||||||
import com.tangem.core.ui.message.SnackbarMessage
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||||
|
import com.tangem.domain.account.supplier.MultiAccountListSupplier
|
||||||
|
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
||||||
import com.tangem.domain.qrscanning.models.QrResultSource
|
import com.tangem.domain.qrscanning.models.QrResultSource
|
||||||
import com.tangem.domain.qrscanning.models.SourceType
|
import com.tangem.domain.qrscanning.models.SourceType
|
||||||
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
||||||
|
|
@ -28,14 +31,16 @@ import com.tangem.domain.walletconnect.model.WcSession
|
||||||
import com.tangem.domain.walletconnect.usecase.WcSessionsUseCase
|
import com.tangem.domain.walletconnect.usecase.WcSessionsUseCase
|
||||||
import com.tangem.domain.walletconnect.usecase.disconnect.WcDisconnectUseCase
|
import com.tangem.domain.walletconnect.usecase.disconnect.WcDisconnectUseCase
|
||||||
import com.tangem.features.walletconnect.connections.components.WcConnectionsComponent
|
import com.tangem.features.walletconnect.connections.components.WcConnectionsComponent
|
||||||
|
import com.tangem.features.walletconnect.connections.entity.WcConnections
|
||||||
import com.tangem.features.walletconnect.connections.entity.WcConnectionsState
|
import com.tangem.features.walletconnect.connections.entity.WcConnectionsState
|
||||||
import com.tangem.features.walletconnect.connections.entity.WcConnectionsTopAppBarConfig
|
import com.tangem.features.walletconnect.connections.entity.WcConnectionsTopAppBarConfig
|
||||||
|
import com.tangem.features.walletconnect.connections.model.transformers.WcSessionsAccountModeTransformer
|
||||||
import com.tangem.features.walletconnect.connections.model.transformers.WcSessionsTransformer
|
import com.tangem.features.walletconnect.connections.model.transformers.WcSessionsTransformer
|
||||||
import com.tangem.features.walletconnect.connections.routes.WcConnectionsBottomSheetConfig
|
import com.tangem.features.walletconnect.connections.routes.WcConnectionsBottomSheetConfig
|
||||||
import com.tangem.features.walletconnect.impl.R
|
import com.tangem.features.walletconnect.impl.R
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
import com.tangem.utils.transformer.Transformer
|
||||||
import com.tangem.utils.transformer.update
|
import com.tangem.utils.transformer.update
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
@ -48,6 +53,9 @@ internal class WcConnectionsModel @Inject constructor(
|
||||||
private val listenToQrScanningUseCase: ListenToQrScanningUseCase,
|
private val listenToQrScanningUseCase: ListenToQrScanningUseCase,
|
||||||
private val wcSessionsUseCase: WcSessionsUseCase,
|
private val wcSessionsUseCase: WcSessionsUseCase,
|
||||||
private val wcDisconnectUseCase: WcDisconnectUseCase,
|
private val wcDisconnectUseCase: WcDisconnectUseCase,
|
||||||
|
private val multiAccountListSupplier: MultiAccountListSupplier,
|
||||||
|
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||||
|
accountsFeatureToggles: AccountsFeatureToggles,
|
||||||
private val wcPairService: WcPairService,
|
private val wcPairService: WcPairService,
|
||||||
override val dispatchers: CoroutineDispatcherProvider,
|
override val dispatchers: CoroutineDispatcherProvider,
|
||||||
analytics: AnalyticsEventHandler,
|
analytics: AnalyticsEventHandler,
|
||||||
|
|
@ -62,7 +70,11 @@ internal class WcConnectionsModel @Inject constructor(
|
||||||
init {
|
init {
|
||||||
analytics.send(WcAnalyticEvents.ScreenOpened)
|
analytics.send(WcAnalyticEvents.ScreenOpened)
|
||||||
listenQrUpdates()
|
listenQrUpdates()
|
||||||
|
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||||
listenWcSessions()
|
listenWcSessions()
|
||||||
|
} else {
|
||||||
|
listenWcSessionsOld()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun listenQrUpdates() {
|
private fun listenQrUpdates() {
|
||||||
|
|
@ -86,7 +98,7 @@ internal class WcConnectionsModel @Inject constructor(
|
||||||
.launchIn(modelScope)
|
.launchIn(modelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun listenWcSessions() {
|
private fun listenWcSessionsOld() {
|
||||||
wcSessionsUseCase.invoke()
|
wcSessionsUseCase.invoke()
|
||||||
.conflate()
|
.conflate()
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
|
|
@ -101,6 +113,31 @@ internal class WcConnectionsModel @Inject constructor(
|
||||||
.launchIn(modelScope)
|
.launchIn(modelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun listenWcSessions() {
|
||||||
|
combine(
|
||||||
|
flow = wcSessionsUseCase.invoke().distinctUntilChanged(),
|
||||||
|
flow2 = isAccountsModeEnabledUseCase(),
|
||||||
|
flow3 = multiAccountListSupplier(Unit),
|
||||||
|
transform = { sessionsMap, isAccountMode, accountList ->
|
||||||
|
val transformer: Transformer<WcConnectionsState> =
|
||||||
|
if (isAccountMode) {
|
||||||
|
WcSessionsAccountModeTransformer(
|
||||||
|
sessionsMap = sessionsMap,
|
||||||
|
accountList = accountList,
|
||||||
|
openAppInfoModal = ::openAppInfoModal,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
WcSessionsTransformer(
|
||||||
|
sessionsMap = sessionsMap,
|
||||||
|
openAppInfoModal = ::openAppInfoModal,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
uiState.update(transformer)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.launchIn(modelScope)
|
||||||
|
}
|
||||||
|
|
||||||
private fun openAppInfoModal(session: WcSession) {
|
private fun openAppInfoModal(session: WcSession) {
|
||||||
bottomSheetNavigation.activate(WcConnectionsBottomSheetConfig.ConnectedApp(session.sdkModel.topic))
|
bottomSheetNavigation.activate(WcConnectionsBottomSheetConfig.ConnectedApp(session.sdkModel.topic))
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +181,7 @@ internal class WcConnectionsModel @Inject constructor(
|
||||||
onClick = ::showDisconnectAllDialog,
|
onClick = ::showDisconnectAllDialog,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
connections = persistentListOf(),
|
connections = WcConnections.Loading,
|
||||||
onNewConnectionClick = ::openQrScanScreen,
|
onNewConnectionClick = ::openQrScanScreen,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
package com.tangem.features.walletconnect.connections.model.transformers
|
||||||
|
|
||||||
|
import com.tangem.common.ui.account.AccountTitleUM
|
||||||
|
import com.tangem.common.ui.account.toUM
|
||||||
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
import com.tangem.domain.account.models.AccountList
|
||||||
|
import com.tangem.domain.models.account.Account
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.models.wallet.isLocked
|
||||||
|
import com.tangem.domain.walletconnect.model.WcSession
|
||||||
|
import com.tangem.features.walletconnect.connections.entity.WcConnectedAppInfo
|
||||||
|
import com.tangem.features.walletconnect.connections.entity.WcConnections
|
||||||
|
import com.tangem.features.walletconnect.connections.entity.WcConnectionsItem
|
||||||
|
import com.tangem.features.walletconnect.connections.entity.WcConnectionsState
|
||||||
|
import com.tangem.utils.transformer.Transformer
|
||||||
|
import kotlinx.collections.immutable.toPersistentList
|
||||||
|
|
||||||
|
internal class WcSessionsAccountModeTransformer(
|
||||||
|
private val sessionsMap: Map<UserWallet, List<WcSession>>,
|
||||||
|
private val accountList: List<AccountList>,
|
||||||
|
private val openAppInfoModal: (WcSession) -> Unit,
|
||||||
|
) : Transformer<WcConnectionsState> {
|
||||||
|
|
||||||
|
override fun transform(prevState: WcConnectionsState): WcConnectionsState {
|
||||||
|
val items = mutableListOf<WcConnectionsItem>()
|
||||||
|
val lockedWallet = mutableListOf<WcConnectionsItem.WalletHeader>()
|
||||||
|
|
||||||
|
accountList.forEach { accountList ->
|
||||||
|
val userWallet = sessionsMap.keys.find { it.walletId == accountList.userWalletId }
|
||||||
|
?: return@forEach
|
||||||
|
val sessions = sessionsMap[userWallet] ?: return@forEach
|
||||||
|
|
||||||
|
if (userWallet.isLocked) {
|
||||||
|
val lockedItem = WcConnectionsItem.WalletHeader(
|
||||||
|
id = userWallet.walletId.stringValue,
|
||||||
|
walletName = userWallet.name,
|
||||||
|
isLocked = true,
|
||||||
|
)
|
||||||
|
lockedWallet.add(lockedItem)
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
|
val walletHeader = WcConnectionsItem.WalletHeader(
|
||||||
|
id = userWallet.walletId.stringValue,
|
||||||
|
walletName = userWallet.name,
|
||||||
|
isLocked = false,
|
||||||
|
)
|
||||||
|
items.add(walletHeader)
|
||||||
|
|
||||||
|
accountList.accounts.forEach accountsForEach@{ account ->
|
||||||
|
val accountSessions = sessions.filter { it.account?.accountId == account.accountId }
|
||||||
|
if (accountSessions.isEmpty()) return@accountsForEach
|
||||||
|
val connectedApps = accountSessions.map { dappSession ->
|
||||||
|
with(dappSession.sdkModel) {
|
||||||
|
WcConnectedAppInfo(
|
||||||
|
name = appMetaData.name,
|
||||||
|
iconUrl = appMetaData.icons.firstOrNull().orEmpty(),
|
||||||
|
subtitle = WcAppSubtitleConverter.convert(appMetaData),
|
||||||
|
verifiedState = WcDAppVerifiedStateConverter {}
|
||||||
|
.convert(dappSession.securityStatus to appMetaData.name),
|
||||||
|
onClick = { openAppInfoModal(dappSession) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val accountIcon = when (account) {
|
||||||
|
is Account.CryptoPortfolio -> account.icon
|
||||||
|
}
|
||||||
|
|
||||||
|
val accountTitle = AccountTitleUM.Account(
|
||||||
|
prefixText = TextReference.EMPTY,
|
||||||
|
name = account.accountName.toUM().value,
|
||||||
|
icon = accountIcon.toUM(),
|
||||||
|
)
|
||||||
|
|
||||||
|
val accountConnections = WcConnectionsItem.PortfolioConnections(
|
||||||
|
id = userWallet.walletId.stringValue + account.accountId.value,
|
||||||
|
portfolioTitle = accountTitle,
|
||||||
|
connectedApps = connectedApps.toPersistentList(),
|
||||||
|
)
|
||||||
|
items.add(accountConnections)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return WcConnectionsState(
|
||||||
|
topAppBarConfig = prevState.topAppBarConfig,
|
||||||
|
connections = WcConnections.AccountMode(items.plus(lockedWallet).toPersistentList()),
|
||||||
|
onNewConnectionClick = prevState.onNewConnectionClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package com.tangem.features.walletconnect.connections.model.transformers
|
package com.tangem.features.walletconnect.connections.model.transformers
|
||||||
|
|
||||||
import com.tangem.domain.walletconnect.model.WcSession
|
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.walletconnect.model.WcSession
|
||||||
import com.tangem.features.walletconnect.connections.entity.WcConnectedAppInfo
|
import com.tangem.features.walletconnect.connections.entity.WcConnectedAppInfo
|
||||||
|
import com.tangem.features.walletconnect.connections.entity.WcConnections
|
||||||
import com.tangem.features.walletconnect.connections.entity.WcConnectionsState
|
import com.tangem.features.walletconnect.connections.entity.WcConnectionsState
|
||||||
import com.tangem.features.walletconnect.connections.entity.WcConnectionsUM
|
import com.tangem.features.walletconnect.connections.entity.WcConnectionsUM
|
||||||
import com.tangem.utils.transformer.Transformer
|
import com.tangem.utils.transformer.Transformer
|
||||||
|
|
@ -14,8 +15,7 @@ internal class WcSessionsTransformer(
|
||||||
) : Transformer<WcConnectionsState> {
|
) : Transformer<WcConnectionsState> {
|
||||||
|
|
||||||
override fun transform(prevState: WcConnectionsState): WcConnectionsState {
|
override fun transform(prevState: WcConnectionsState): WcConnectionsState {
|
||||||
return prevState.copy(
|
val newConnections = sessionsMap.map { (wallet, sessions) ->
|
||||||
connections = sessionsMap.map { (wallet, sessions) ->
|
|
||||||
WcConnectionsUM(
|
WcConnectionsUM(
|
||||||
userWalletId = wallet.walletId.stringValue,
|
userWalletId = wallet.walletId.stringValue,
|
||||||
walletName = wallet.name,
|
walletName = wallet.name,
|
||||||
|
|
@ -32,7 +32,11 @@ internal class WcSessionsTransformer(
|
||||||
}
|
}
|
||||||
}.toPersistentList(),
|
}.toPersistentList(),
|
||||||
)
|
)
|
||||||
}.toPersistentList(),
|
}.toPersistentList()
|
||||||
|
return WcConnectionsState(
|
||||||
|
topAppBarConfig = prevState.topAppBarConfig,
|
||||||
|
connections = WcConnections.WalletMode(newConnections),
|
||||||
|
onNewConnectionClick = prevState.onNewConnectionClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -14,11 +14,13 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.util.fastForEach
|
import androidx.compose.ui.util.fastForEach
|
||||||
|
import com.tangem.common.ui.account.AccountTitle
|
||||||
|
import com.tangem.common.ui.account.AccountTitleUM
|
||||||
import com.tangem.core.ui.components.SecondaryButton
|
import com.tangem.core.ui.components.SecondaryButton
|
||||||
|
import com.tangem.core.ui.components.account.AccountIconSize
|
||||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
|
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
|
||||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||||
|
|
@ -35,6 +37,7 @@ import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday
|
||||||
import com.tangem.core.ui.utils.toTimeFormat
|
import com.tangem.core.ui.utils.toTimeFormat
|
||||||
import com.tangem.features.walletconnect.connections.entity.*
|
import com.tangem.features.walletconnect.connections.entity.*
|
||||||
import com.tangem.features.walletconnect.impl.R
|
import com.tangem.features.walletconnect.impl.R
|
||||||
|
import com.tangem.features.walletconnect.transaction.ui.sign.accountPortfolioName
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
||||||
|
|
@ -137,9 +140,17 @@ private fun AppInfoFirstBlock(state: WcConnectedAppInfoUM, modifier: Modifier =
|
||||||
subtitle = state.appSubtitle,
|
subtitle = state.appSubtitle,
|
||||||
verifiedDAppState = state.verifiedDAppState,
|
verifiedDAppState = state.verifiedDAppState,
|
||||||
)
|
)
|
||||||
HorizontalDivider(thickness = 1.dp, color = TangemTheme.colors.stroke.primary)
|
if (state.portfolioName != null) {
|
||||||
|
HorizontalDivider(thickness = 0.5.dp, color = TangemTheme.colors.stroke.primary)
|
||||||
|
PortfolioName(state.portfolioName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun PortfolioName(portfolioName: AccountTitleUM, modifier: Modifier = Modifier) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(TangemTheme.dimens.spacing12),
|
.padding(TangemTheme.dimens.spacing12),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
|
@ -152,27 +163,29 @@ private fun AppInfoFirstBlock(state: WcConnectedAppInfoUM, modifier: Modifier =
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = TangemTheme.colors.icon.accent,
|
tint = TangemTheme.colors.icon.accent,
|
||||||
)
|
)
|
||||||
|
val leftText: String = when (portfolioName) {
|
||||||
|
is AccountTitleUM.Account -> stringResourceSafe(R.string.common_account)
|
||||||
|
is AccountTitleUM.Text -> stringResourceSafe(R.string.wc_common_wallet)
|
||||||
|
}
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(start = TangemTheme.dimens.spacing4)
|
.padding(start = TangemTheme.dimens.spacing4)
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.testTag(WalletConnectDetailsBottomSheetTestTags.WALLET_TITLE),
|
.testTag(WalletConnectDetailsBottomSheetTestTags.WALLET_TITLE),
|
||||||
text = stringResourceSafe(R.string.manage_tokens_network_selector_wallet),
|
text = leftText,
|
||||||
style = TangemTheme.typography.body1,
|
style = TangemTheme.typography.body1,
|
||||||
color = TangemTheme.colors.text.primary1,
|
color = TangemTheme.colors.text.primary1,
|
||||||
)
|
)
|
||||||
Text(
|
AccountTitle(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(start = TangemTheme.dimens.spacing16)
|
.padding(start = TangemTheme.dimens.spacing16)
|
||||||
.weight(1f)
|
|
||||||
.testTag(WalletConnectDetailsBottomSheetTestTags.WALLET_NAME),
|
.testTag(WalletConnectDetailsBottomSheetTestTags.WALLET_NAME),
|
||||||
text = state.walletName,
|
accountTitleUM = portfolioName,
|
||||||
textAlign = TextAlign.End,
|
textStyle = TangemTheme.typography.body1,
|
||||||
style = TangemTheme.typography.body1,
|
textColor = TangemTheme.colors.text.tertiary,
|
||||||
color = TangemTheme.colors.text.tertiary,
|
iconSize = AccountIconSize.Small,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -194,7 +207,6 @@ private fun NetworksBlock(networks: ImmutableList<WcNetworkInfoItem.Required>, m
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun WcConnectedAppInfoBS_Preview() {
|
private fun WcConnectedAppInfoBS_Preview() {
|
||||||
TangemThemePreview {
|
TangemThemePreview {
|
||||||
|
|
@ -205,7 +217,48 @@ private fun WcConnectedAppInfoBS_Preview() {
|
||||||
verifiedDAppState = VerifiedDAppState.Verified {},
|
verifiedDAppState = VerifiedDAppState.Verified {},
|
||||||
isVerified = true,
|
isVerified = true,
|
||||||
appSubtitle = "react-app.walletconnect.com",
|
appSubtitle = "react-app.walletconnect.com",
|
||||||
walletName = "Tangem 2.0",
|
portfolioName = accountPortfolioName,
|
||||||
|
connectingTime = System.currentTimeMillis(),
|
||||||
|
networks = persistentListOf(
|
||||||
|
WcNetworkInfoItem.Required(
|
||||||
|
id = "1",
|
||||||
|
icon = R.drawable.img_optimism_22,
|
||||||
|
name = "img_optimism_22img_optimism_22",
|
||||||
|
symbol = "optimism",
|
||||||
|
),
|
||||||
|
WcNetworkInfoItem.Required(
|
||||||
|
id = "2",
|
||||||
|
icon = R.drawable.img_bsc_22,
|
||||||
|
name = "img_bsc_22",
|
||||||
|
symbol = "bsc",
|
||||||
|
),
|
||||||
|
WcNetworkInfoItem.Required(
|
||||||
|
id = "3",
|
||||||
|
icon = R.drawable.img_solana_22,
|
||||||
|
name = "img_solana_22",
|
||||||
|
symbol = "solana",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
disconnectButtonConfig = WcPrimaryButtonConfig(showProgress = false, enabled = true, onClick = {}),
|
||||||
|
onDismiss = {},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
private fun WcConnectedAppInfoBS_OneWallet_Preview() {
|
||||||
|
TangemThemePreview {
|
||||||
|
WcConnectedAppInfoBS(
|
||||||
|
state = WcConnectedAppInfoUM(
|
||||||
|
appName = "React App",
|
||||||
|
appIcon = "",
|
||||||
|
verifiedDAppState = VerifiedDAppState.Verified {},
|
||||||
|
isVerified = true,
|
||||||
|
appSubtitle = "react-app.walletconnect.com",
|
||||||
|
portfolioName = null,
|
||||||
connectingTime = System.currentTimeMillis(),
|
connectingTime = System.currentTimeMillis(),
|
||||||
networks = persistentListOf(
|
networks = persistentListOf(
|
||||||
WcNetworkInfoItem.Required(
|
WcNetworkInfoItem.Required(
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,22 @@ import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.vectorResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
|
@ -27,12 +32,14 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.util.fastForEach
|
import androidx.compose.ui.util.fastForEach
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
|
import com.tangem.common.ui.account.AccountTitle
|
||||||
import com.tangem.core.ui.components.BottomFade
|
import com.tangem.core.ui.components.BottomFade
|
||||||
import com.tangem.core.ui.components.PrimaryButton
|
import com.tangem.core.ui.components.PrimaryButton
|
||||||
import com.tangem.core.ui.components.appbar.TopAppBarButton
|
import com.tangem.core.ui.components.appbar.TopAppBarButton
|
||||||
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownItem
|
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownItem
|
||||||
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenu
|
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenu
|
||||||
import com.tangem.core.ui.components.snackbar.TangemSnackbarHost
|
import com.tangem.core.ui.components.snackbar.TangemSnackbarHost
|
||||||
|
import com.tangem.core.ui.extensions.conditional
|
||||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
|
|
@ -42,6 +49,8 @@ import com.tangem.features.walletconnect.connections.ui.preview.WcConnectionsPre
|
||||||
import com.tangem.features.walletconnect.impl.R
|
import com.tangem.features.walletconnect.impl.R
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
|
private const val LOCKED_WALLET_ALPHA = 0.5f
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun WcConnectionsContent(
|
internal fun WcConnectionsContent(
|
||||||
state: WcConnectionsState,
|
state: WcConnectionsState,
|
||||||
|
|
@ -88,15 +97,21 @@ internal fun WcConnectionsContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Content(
|
private fun Content(connections: WcConnections, onNewConnectionClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||||
connections: ImmutableList<WcConnectionsUM>,
|
when {
|
||||||
onNewConnectionClick: () -> Unit,
|
connections is WcConnections.Loading -> return
|
||||||
modifier: Modifier = Modifier,
|
!connections.isNotEmpty() -> EmptyConnectionsBlock(
|
||||||
) {
|
modifier = modifier,
|
||||||
if (connections.isEmpty()) {
|
onNewConnectionClick = onNewConnectionClick,
|
||||||
EmptyConnectionsBlock(modifier = modifier, onNewConnectionClick = onNewConnectionClick)
|
)
|
||||||
} else {
|
connections is WcConnections.AccountMode -> AccountModeContent(
|
||||||
ConnectionsBlock(modifier = modifier, connections = connections)
|
modifier = modifier,
|
||||||
|
items = connections.items,
|
||||||
|
)
|
||||||
|
connections is WcConnections.WalletMode -> ConnectionsBlock(
|
||||||
|
modifier = modifier,
|
||||||
|
connections = connections.connections,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,6 +184,59 @@ private fun ConnectionsBlock(connections: ImmutableList<WcConnectionsUM>, modifi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun AccountModeContent(items: ImmutableList<WcConnectionsItem>, modifier: Modifier = Modifier) {
|
||||||
|
Box(modifier = modifier) {
|
||||||
|
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = PaddingValues(
|
||||||
|
start = TangemTheme.dimens.spacing16,
|
||||||
|
end = TangemTheme.dimens.spacing16,
|
||||||
|
bottom = TangemTheme.dimens.spacing76 + bottomBarHeight,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
itemsIndexed(
|
||||||
|
items = items,
|
||||||
|
key = { _, item -> item.id },
|
||||||
|
itemContent = { index, item ->
|
||||||
|
val previousItem = items.getOrNull(index.dec())
|
||||||
|
|
||||||
|
val itemModifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.getOffsetModifier(item, previousItem)
|
||||||
|
when (item) {
|
||||||
|
is WcConnectionsItem.WalletHeader -> WalletHeader(item, itemModifier)
|
||||||
|
is WcConnectionsItem.PortfolioConnections -> PortfolioItem(
|
||||||
|
modifier = itemModifier
|
||||||
|
.background(
|
||||||
|
color = TangemTheme.colors.background.primary,
|
||||||
|
shape = RoundedCornerShape(TangemTheme.dimens.radius14),
|
||||||
|
)
|
||||||
|
.clip(RoundedCornerShape(TangemTheme.dimens.radius14)),
|
||||||
|
connection = item,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
BottomFade(modifier = Modifier.align(Alignment.BottomCenter))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Modifier.getOffsetModifier(item: WcConnectionsItem, previousItem: WcConnectionsItem?): Modifier = when {
|
||||||
|
item is WcConnectionsItem.WalletHeader && previousItem == null -> padding(top = 8.dp)
|
||||||
|
item is WcConnectionsItem.WalletHeader && previousItem !is WcConnectionsItem.WalletHeader ->
|
||||||
|
padding(top = 16.dp)
|
||||||
|
item is WcConnectionsItem.WalletHeader && previousItem is WcConnectionsItem.WalletHeader ->
|
||||||
|
padding(top = 8.dp)
|
||||||
|
item is WcConnectionsItem.PortfolioConnections && previousItem is WcConnectionsItem.WalletHeader ->
|
||||||
|
padding(top = 8.dp)
|
||||||
|
item is WcConnectionsItem.PortfolioConnections && previousItem is WcConnectionsItem.PortfolioConnections ->
|
||||||
|
padding(top = 8.dp)
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ConnectionItem(connection: WcConnectionsUM, modifier: Modifier = Modifier) {
|
private fun ConnectionItem(connection: WcConnectionsUM, modifier: Modifier = Modifier) {
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
|
|
@ -195,6 +263,69 @@ private fun ConnectionItem(connection: WcConnectionsUM, modifier: Modifier = Mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun WalletHeader(connection: WcConnectionsItem.WalletHeader, modifier: Modifier = Modifier) {
|
||||||
|
Row(
|
||||||
|
modifier = modifier
|
||||||
|
.padding(horizontal = 8.dp, vertical = 2.dp)
|
||||||
|
.conditional(connection.isLocked) { alpha(LOCKED_WALLET_ALPHA) },
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
text = connection.walletName,
|
||||||
|
style = TangemTheme.typography.subtitle1,
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (connection.isLocked) {
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.background(
|
||||||
|
color = TangemTheme.colors.button.secondary,
|
||||||
|
shape = CircleShape,
|
||||||
|
)
|
||||||
|
.padding(4.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
tint = TangemTheme.colors.icon.informative,
|
||||||
|
imageVector = ImageVector.vectorResource(id = R.drawable.ic_locked_24),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun PortfolioItem(connection: WcConnectionsItem.PortfolioConnections, modifier: Modifier = Modifier) {
|
||||||
|
Column(modifier = modifier) {
|
||||||
|
key(connection.id) {
|
||||||
|
AccountTitle(
|
||||||
|
textStyle = TangemTheme.typography.caption1,
|
||||||
|
textColor = TangemTheme.colors.text.primary1,
|
||||||
|
accountTitleUM = connection.portfolioTitle,
|
||||||
|
modifier = Modifier.padding(top = 12.dp, bottom = 4.dp, start = 12.dp, end = 12.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
connection.connectedApps.fastForEach { appInfo ->
|
||||||
|
key("${connection.id}_${appInfo.name}_${appInfo.iconUrl}") {
|
||||||
|
AppInfoItem(
|
||||||
|
appInfo = appInfo,
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable(onClick = appInfo.onClick)
|
||||||
|
.padding(all = 12.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun AppInfoItem(appInfo: WcConnectedAppInfo, modifier: Modifier = Modifier) {
|
private fun AppInfoItem(appInfo: WcConnectedAppInfo, modifier: Modifier = Modifier) {
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -331,7 +462,9 @@ private fun WcConnectionsContentPreview(
|
||||||
|
|
||||||
private class WcConnectionsStateProvider : CollectionPreviewParameterProvider<WcConnectionsState>(
|
private class WcConnectionsStateProvider : CollectionPreviewParameterProvider<WcConnectionsState>(
|
||||||
listOf(
|
listOf(
|
||||||
|
WcConnectionsPreviewData.loadingState,
|
||||||
WcConnectionsPreviewData.stateWithEmptyConnections,
|
WcConnectionsPreviewData.stateWithEmptyConnections,
|
||||||
WcConnectionsPreviewData.fullState,
|
WcConnectionsPreviewData.fullState,
|
||||||
|
WcConnectionsPreviewData.accountState,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -7,8 +7,10 @@ import com.tangem.core.ui.extensions.themedColor
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.features.walletconnect.connections.entity.*
|
import com.tangem.features.walletconnect.connections.entity.*
|
||||||
import com.tangem.features.walletconnect.impl.R
|
import com.tangem.features.walletconnect.impl.R
|
||||||
|
import com.tangem.features.walletconnect.transaction.ui.sign.accountPortfolioName
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
internal object WcConnectionsPreviewData {
|
internal object WcConnectionsPreviewData {
|
||||||
private const val BASE_URL = "https://raw.githubusercontent.com/TaranVH/LOGOS/refs/heads/master/Crypto"
|
private const val BASE_URL = "https://raw.githubusercontent.com/TaranVH/LOGOS/refs/heads/master/Crypto"
|
||||||
|
|
@ -125,8 +127,62 @@ internal object WcConnectionsPreviewData {
|
||||||
onClick = { },
|
onClick = { },
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
connections = persistentListOf(),
|
connections = WcConnections.WalletMode(persistentListOf()),
|
||||||
onNewConnectionClick = {},
|
onNewConnectionClick = {},
|
||||||
)
|
)
|
||||||
val fullState = stateWithEmptyConnections.copy(connections = connections)
|
|
||||||
|
val connectedDapp
|
||||||
|
get() = WcConnectedAppInfo(
|
||||||
|
name = "React app",
|
||||||
|
iconUrl = "$BASE_URL/LiteCoin.png",
|
||||||
|
subtitle = "https://react-app.walletconnect.com/",
|
||||||
|
verifiedState = VerifiedDAppState.Verified {},
|
||||||
|
onClick = { Timber.d("React app clicked") },
|
||||||
|
)
|
||||||
|
|
||||||
|
val walletHeader
|
||||||
|
get() = WcConnectionsItem.WalletHeader(
|
||||||
|
id = UUID.randomUUID().toString(),
|
||||||
|
walletName = "User Wallet",
|
||||||
|
isLocked = false,
|
||||||
|
)
|
||||||
|
|
||||||
|
val lockedWallet
|
||||||
|
get() = WcConnectionsItem.WalletHeader(
|
||||||
|
id = UUID.randomUUID().toString(),
|
||||||
|
walletName = "Locked Wallet",
|
||||||
|
isLocked = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
val accountStateItems
|
||||||
|
get() = persistentListOf(
|
||||||
|
walletHeader,
|
||||||
|
WcConnectionsItem.PortfolioConnections(
|
||||||
|
id = UUID.randomUUID().toString(),
|
||||||
|
portfolioTitle = accountPortfolioName,
|
||||||
|
connectedApps = persistentListOf(connectedDapp),
|
||||||
|
),
|
||||||
|
walletHeader,
|
||||||
|
WcConnectionsItem.PortfolioConnections(
|
||||||
|
id = UUID.randomUUID().toString(),
|
||||||
|
portfolioTitle = accountPortfolioName,
|
||||||
|
connectedApps = persistentListOf(connectedDapp, connectedDapp),
|
||||||
|
),
|
||||||
|
WcConnectionsItem.PortfolioConnections(
|
||||||
|
id = UUID.randomUUID().toString(),
|
||||||
|
portfolioTitle = accountPortfolioName,
|
||||||
|
connectedApps = persistentListOf(connectedDapp),
|
||||||
|
),
|
||||||
|
WcConnectionsItem.PortfolioConnections(
|
||||||
|
id = UUID.randomUUID().toString(),
|
||||||
|
portfolioTitle = accountPortfolioName,
|
||||||
|
connectedApps = persistentListOf(connectedDapp),
|
||||||
|
),
|
||||||
|
lockedWallet,
|
||||||
|
lockedWallet,
|
||||||
|
)
|
||||||
|
|
||||||
|
val fullState = stateWithEmptyConnections.copy(connections = WcConnections.WalletMode(connections))
|
||||||
|
val accountState = stateWithEmptyConnections.copy(connections = WcConnections.AccountMode(accountStateItems))
|
||||||
|
val loadingState = stateWithEmptyConnections.copy(connections = WcConnections.Loading)
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue