From e10334a9356f96ccea778b5f196eb7ea08be5be5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 23 Mar 2026 13:58:49 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../com/tangem/tap/LockUserWalletsTimer.kt | 4 ++ .../main/java/com/tangem/tap/MainActivity.kt | 18 ++++++++- .../ui/extensions/UserInteractionTracking.kt | 40 +++++++++++++++++++ .../data/wallets/hot/TangemHotWalletSigner.kt | 5 ++- .../usecase/SendTransactionUseCase.kt | 3 ++ .../HotAccessCodeRequestFullScreenContent.kt | 10 ++++- 6 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 core/ui/src/main/java/com/tangem/core/ui/extensions/UserInteractionTracking.kt diff --git a/app/src/main/java/com/tangem/tap/LockUserWalletsTimer.kt b/app/src/main/java/com/tangem/tap/LockUserWalletsTimer.kt index 809f2808bc..3124e26244 100644 --- a/app/src/main/java/com/tangem/tap/LockUserWalletsTimer.kt +++ b/app/src/main/java/com/tangem/tap/LockUserWalletsTimer.kt @@ -9,6 +9,7 @@ import androidx.work.WorkManager import com.tangem.common.routing.AppRoute import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.settings.repositories.SettingsRepository +import com.tangem.domain.wallets.hot.HotWalletPasswordRequester import com.tangem.domain.wallets.usecase.ClearAllHotWalletContextualUnlockUseCase import com.tangem.tap.LockTimerWorker.Companion.TAG import com.tangem.tap.common.extensions.dispatchNavigationAction @@ -28,6 +29,7 @@ internal class LockUserWalletsTimer( private val userWalletsListRepository: UserWalletsListRepository, private val coroutineScope: CoroutineScope, private val clearAllHotWalletContextualUnlockUseCase: ClearAllHotWalletContextualUnlockUseCase, + private val passwordRequester: HotWalletPasswordRequester, ) : LifecycleOwner by context as LifecycleOwner, DefaultLifecycleObserver { @@ -53,6 +55,7 @@ internal class LockUserWalletsTimer( ) if (shouldOpenWelcomeScreenOnResume) { + passwordRequester.dismiss() clearAllHotWalletContextualUnlockUseCase.invoke() store.dispatchNavigationAction { replaceAll(AppRoute.Welcome()) } settingsRepository.setShouldOpenWelcomeScreenOnResume(value = false) @@ -116,6 +119,7 @@ internal class LockUserWalletsTimer( start() } .onRight { + passwordRequester.dismiss() clearAllHotWalletContextualUnlockUseCase.invoke() store.dispatchNavigationAction { replaceAll(AppRoute.Welcome()) } } diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index ea612e1a2d..d6c1a7abf3 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -17,6 +17,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb @@ -29,6 +30,8 @@ import com.tangem.common.routing.deeplink.DeeplinkConst.WEBLINK_KEY import com.tangem.common.routing.deeplink.PayloadToDeeplinkConverter import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.ui.extensions.LocalUserInteractionTracker +import com.tangem.core.ui.extensions.UserInteractionTracker import com.tangem.core.decompose.di.RootAppComponentContext import com.tangem.core.navigation.url.UrlOpener import com.tangem.data.balancehiding.DefaultDeviceFlipDetector @@ -43,6 +46,7 @@ import com.tangem.domain.settings.SetGoogleServicesAvailabilityUseCase import com.tangem.domain.settings.ShouldInitiallyAskPermissionUseCase import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.staking.SendUnsubmittedHashesUseCase +import com.tangem.domain.wallets.hot.HotWalletPasswordRequester import com.tangem.domain.wallets.usecase.ClearAllHotWalletContextualUnlockUseCase import com.tangem.features.tester.api.TesterMenuLauncher import com.tangem.google.GoogleServicesHelper @@ -160,6 +164,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder { @Inject internal lateinit var clearAllHotWalletContextualUnlockUseCase: ClearAllHotWalletContextualUnlockUseCase + @Inject + internal lateinit var passwordRequester: HotWalletPasswordRequester + private val viewModel: MainViewModel by viewModels() private lateinit var appThemeModeFlow: SharedFlow @@ -231,8 +238,16 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder { launchMode = backgroundScanIntentHandler.getInitScreenLaunchMode(intent), ) + val userInteractionTracker = object : UserInteractionTracker { + override fun onUserInteraction() { + lockUserWalletsTimer?.restart() + } + } + setContent { - routingComponent.Content(Modifier.fillMaxSize()) + CompositionLocalProvider(LocalUserInteractionTracker provides userInteractionTracker) { + routingComponent.Content(Modifier.fillMaxSize()) + } } } @@ -249,6 +264,7 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder { coroutineScope = mainScope, userWalletsListRepository = userWalletsListRepository, clearAllHotWalletContextualUnlockUseCase = clearAllHotWalletContextualUnlockUseCase, + passwordRequester = passwordRequester, ) store.dispatch( diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/UserInteractionTracking.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/UserInteractionTracking.kt new file mode 100644 index 0000000000..14adf10f6b --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/UserInteractionTracking.kt @@ -0,0 +1,40 @@ +package com.tangem.core.ui.extensions + +import androidx.compose.foundation.gestures.awaitEachGesture +import androidx.compose.foundation.gestures.awaitFirstDown +import androidx.compose.foundation.gestures.waitForUpOrCancellation +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.onPreviewKeyEvent +import androidx.compose.ui.input.key.type +import androidx.compose.ui.input.pointer.pointerInput + +val LocalUserInteractionTracker = staticCompositionLocalOf { null } + +interface UserInteractionTracker { + fun onUserInteraction() +} + +fun Modifier.trackUserInteraction(tracker: UserInteractionTracker?): Modifier { + if (tracker == null) return this + + return this + .pointerInput(Unit) { + awaitEachGesture { + val down = awaitFirstDown(requireUnconsumed = false) + + if (down.pressed) { + tracker.onUserInteraction() + } + + waitForUpOrCancellation() + } + } + .onPreviewKeyEvent { event -> + if (event.type == KeyEventType.KeyDown) { + tracker.onUserInteraction() + } + false + } +} \ No newline at end of file diff --git a/data/wallets/src/main/java/com/tangem/data/wallets/hot/TangemHotWalletSigner.kt b/data/wallets/src/main/java/com/tangem/data/wallets/hot/TangemHotWalletSigner.kt index 58df536d84..99e2bde6ae 100644 --- a/data/wallets/src/main/java/com/tangem/data/wallets/hot/TangemHotWalletSigner.kt +++ b/data/wallets/src/main/java/com/tangem/data/wallets/hot/TangemHotWalletSigner.kt @@ -9,6 +9,7 @@ import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.wallets.hot.HotWalletAccessor import com.tangem.hot.sdk.model.DataToSign import com.tangem.operations.sign.SignData +import com.tangem.utils.coroutines.runSuspendCatching import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -32,7 +33,7 @@ class TangemHotWalletSigner @AssistedInject constructor( TangemSdkError.ExceptionError(IllegalStateException("wallet is locked")), ) - val result = runCatching { + val result = runSuspendCatching { hotWalletAccessor.signHashes( hotWalletId = userWallet.hotWalletId, dataToSign = listOf( @@ -59,7 +60,7 @@ class TangemHotWalletSigner @AssistedInject constructor( dataToSign: List, publicKey: Wallet.PublicKey, ): CompletionResult> { - val result = runCatching { + val result = runSuspendCatching { hotWalletAccessor.signHashes( hotWalletId = userWallet.hotWalletId, dataToSign = dataToSign.map { signData -> diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt index 05bc7a7445..1f273456bb 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt @@ -35,6 +35,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import kotlin.coroutines.cancellation.CancellationException @Suppress("LongParameterList") class SendTransactionUseCase( @@ -96,6 +97,8 @@ class SendTransactionUseCase( is Result.Success -> sendResult.data.right() } } + } catch (e: CancellationException) { + throw e } catch (ex: Exception) { cardSdkConfigRepository.setLinkedTerminal(linkedTerminal) SendTransactionError.DataError(ex.message).left() diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/accesscoderequest/ui/HotAccessCodeRequestFullScreenContent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/accesscoderequest/ui/HotAccessCodeRequestFullScreenContent.kt index 691c5ef55c..bd9c1ce7d9 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/accesscoderequest/ui/HotAccessCodeRequestFullScreenContent.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/accesscoderequest/ui/HotAccessCodeRequestFullScreenContent.kt @@ -18,6 +18,8 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.SecondaryButton +import com.tangem.core.ui.extensions.LocalUserInteractionTracker +import com.tangem.core.ui.extensions.trackUserInteraction import com.tangem.core.ui.components.SpacerH import com.tangem.core.ui.components.SpacerH24 import com.tangem.core.ui.components.appbar.TangemTopAppBar @@ -37,7 +39,13 @@ import com.tangem.features.hotwallet.impl.R @Suppress("MagicNumber", "LongMethod") @Composable internal fun HotAccessCodeRequestFullScreenContent(state: HotAccessCodeRequestUM, modifier: Modifier = Modifier) { - Box(Modifier.fillMaxSize()) { + val userInteractionTracker = LocalUserInteractionTracker.current + + Box( + modifier = Modifier + .fillMaxSize() + .trackUserInteraction(userInteractionTracker), + ) { AnimatedVisibility( modifier = modifier, visible = state.isShown,