Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-23 13:58:49 +05:00
parent 096d1e40c9
commit e10334a935
6 changed files with 76 additions and 4 deletions

View file

@ -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()) }
}

View file

@ -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<AppThemeMode>
@ -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(

View file

@ -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<UserInteractionTracker?> { 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
}
}

View file

@ -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<SignData>,
publicKey: Wallet.PublicKey,
): CompletionResult<Map<ByteArray, ByteArray>> {
val result = runCatching {
val result = runSuspendCatching {
hotWalletAccessor.signHashes(
hotWalletId = userWallet.hotWalletId,
dataToSign = dataToSign.map { signData ->

View file

@ -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()

View file

@ -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,