Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-18 19:22:02 +05:00
parent 1702c4f9b4
commit af5501fb9b
7 changed files with 106 additions and 42 deletions

View file

@ -2,6 +2,8 @@ package com.tangem.tap.di.domain
import com.tangem.domain.walletconnect.CheckIsWalletConnectAvailableUseCase
import com.tangem.domain.walletconnect.repository.WalletConnectRepository
import com.tangem.domain.walletconnect.repository.WcSessionsManager
import com.tangem.domain.walletconnect.usecase.WcSessionsUseCase
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -19,4 +21,10 @@ internal object WalletConnectDomainModule {
): CheckIsWalletConnectAvailableUseCase {
return CheckIsWalletConnectAvailableUseCase(walletConnectRepository = walletConnectRepository)
}
@Provides
@Singleton
fun providesWcSessionsUseCase(sessionsManager: WcSessionsManager): WcSessionsUseCase {
return WcSessionsUseCase(sessionsManager)
}
}

View file

@ -14,7 +14,7 @@ internal data class WcConnectionsState(
internal data class WcConnectionsTopAppBarConfig(
val startButtonUM: TopAppBarButtonUM,
val endActions: ImmutableList<TangemDropdownMenuItem>,
val disconnectAllItem: TangemDropdownMenuItem,
)
internal data class WcConnectionsUM(

View file

@ -6,15 +6,22 @@ import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.EventMessageAction
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.qrscanning.models.SourceType
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
import com.tangem.domain.walletconnect.usecase.WcSessionsUseCase
import com.tangem.features.walletconnect.connections.entity.WcConnectionsState
import com.tangem.features.walletconnect.connections.ui.preview.WcConnectionsPreviewData
import com.tangem.features.walletconnect.connections.entity.WcConnectionsTopAppBarConfig
import com.tangem.features.walletconnect.connections.model.transformers.WcSessionsTransformer
import com.tangem.features.walletconnect.impl.R
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.transformer.update
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.*
import timber.log.Timber
import javax.inject.Inject
@ -24,19 +31,16 @@ internal class WcConnectionsModel @Inject constructor(
private val router: Router,
private val uiMessageSender: UiMessageSender,
private val listenToQrScanningUseCase: ListenToQrScanningUseCase,
private val wcSessionsUseCase: WcSessionsUseCase,
override val dispatchers: CoroutineDispatcherProvider,
) : Model() {
val uiState: StateFlow<WcConnectionsState> = MutableStateFlow(
WcConnectionsPreviewData.stateForModel(
onBackClicked = router::pop,
openQrScanScreen = ::openQrScanScreen,
disconnectAll = ::disconnectAll,
),
).asStateFlow()
val uiState: StateFlow<WcConnectionsState>
field = MutableStateFlow<WcConnectionsState>(getInitialState())
init {
listenQrUpdates()
listenWcSessions()
}
private fun listenQrUpdates() {
@ -49,6 +53,21 @@ internal class WcConnectionsModel @Inject constructor(
.launchIn(modelScope)
}
private fun listenWcSessions() {
wcSessionsUseCase.invoke()
.conflate()
.distinctUntilChanged()
.onEach { sessionsMap ->
uiState.update(
WcSessionsTransformer(
sessionsMap = sessionsMap,
openAppInfoModal = { Timber.d("Open app info for session: $it") },
),
)
}
.launchIn(modelScope)
}
private fun openQrScanScreen() {
router.push(AppRoute.QrScanning(source = AppRoute.QrScanning.Source.WalletConnect))
}
@ -69,4 +88,23 @@ internal class WcConnectionsModel @Inject constructor(
)
uiMessageSender.send(message)
}
private fun getInitialState(): WcConnectionsState {
return WcConnectionsState(
topAppBarConfig = WcConnectionsTopAppBarConfig(
startButtonUM = TopAppBarButtonUM(
iconRes = R.drawable.ic_back_24,
onIconClicked = router::pop,
enabled = true,
),
disconnectAllItem = TangemDropdownMenuItem(
title = resourceReference(R.string.wc_disconnect_all),
textColorProvider = { TangemTheme.colors.text.warning },
onClick = ::disconnectAll,
),
),
connections = persistentListOf(),
onNewConnectionClick = ::openQrScanScreen,
)
}
}

View file

@ -0,0 +1,38 @@
package com.tangem.features.walletconnect.connections.model.transformers
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.walletconnect.model.WcSession
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.walletconnect.connections.entity.WcConnectedAppInfo
import com.tangem.features.walletconnect.connections.entity.WcConnectionsState
import com.tangem.features.walletconnect.connections.entity.WcConnectionsUM
import com.tangem.utils.transformer.Transformer
import kotlinx.collections.immutable.toPersistentList
internal class WcSessionsTransformer(
private val sessionsMap: Map<UserWallet, List<WcSession>>,
private val openAppInfoModal: (WcSession) -> Unit,
) : Transformer<WcConnectionsState> {
override fun transform(prevState: WcConnectionsState): WcConnectionsState {
return prevState.copy(
connections = sessionsMap.map { (wallet, sessions) ->
WcConnectionsUM(
userWalletId = wallet.walletId.stringValue,
walletName = wallet.name,
connectedApps = sessions.map { session ->
with(session.sdkModel) {
WcConnectedAppInfo(
name = appMetaData.name,
iconUrl = appMetaData.icons.firstOrNull().orEmpty(),
subtitle = stringReference(appMetaData.description),
isVerified = false,
onClick = { openAppInfoModal(session) },
)
}
}.toPersistentList(),
)
}.toPersistentList(),
)
}
}

View file

@ -259,12 +259,10 @@ private fun ConnectionsTopBar(
modifier = Modifier.background(TangemTheme.colors.background.primary),
onDismissRequest = { showDropdownMenu = false },
content = {
config.endActions.fastForEach {
TangemDropdownItem(
item = it,
dismissParent = { showDropdownMenu = false },
)
}
TangemDropdownItem(
item = config.disconnectAllItem,
dismissParent = { showDropdownMenu = false },
)
},
)
},

View file

@ -10,7 +10,6 @@ import com.tangem.features.walletconnect.connections.entity.WcConnectionsTopAppB
import com.tangem.features.walletconnect.connections.entity.WcConnectionsUM
import com.tangem.features.walletconnect.impl.R
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import timber.log.Timber
internal object WcConnectionsPreviewData {
@ -111,31 +110,14 @@ internal object WcConnectionsPreviewData {
onIconClicked = {},
enabled = true,
),
endActions = persistentListOf(
TangemDropdownMenuItem(
title = resourceReference(R.string.wc_disconnect_all),
textColorProvider = { TangemTheme.colors.text.warning },
onClick = { },
),
disconnectAllItem = TangemDropdownMenuItem(
title = resourceReference(R.string.wc_disconnect_all),
textColorProvider = { TangemTheme.colors.text.warning },
onClick = { },
),
),
connections = persistentListOf(),
onNewConnectionClick = {},
)
val fullState = stateWithEmptyConnections.copy(connections = connections)
fun stateForModel(
onBackClicked: () -> Unit,
openQrScanScreen: () -> Unit,
disconnectAll: () -> Unit,
): WcConnectionsState {
return fullState.copy(
topAppBarConfig = fullState.topAppBarConfig.copy(
startButtonUM = fullState.topAppBarConfig.startButtonUM.copy(onIconClicked = onBackClicked),
endActions = fullState.topAppBarConfig.endActions
.map { it.copy(onClick = disconnectAll) }
.toImmutableList(),
),
onNewConnectionClick = openQrScanScreen,
)
}
}

View file

@ -1,15 +1,15 @@
package com.tangem.plugin.configuration.configurations
import org.gradle.api.Project
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.model.KotlinAndroidExtension
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
internal fun Project.configureKotlinCompilerOptions() {
kotlinExtension.sourceSets.all {
// https://github.com/Kotlin/KEEP/blob/explicit-backing-fields-re/proposals/explicit-backing-fields.md
languageSettings.enableLanguageFeature("ExplicitBackingFields")
}
project.tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "17"