Updated on 2026-08-14
This commit is contained in:
commit
9488319315
29 changed files with 110 additions and 366 deletions
|
|
@ -1,8 +1,6 @@
|
|||
package com.tangem.tap.common.url
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
import android.content.Intent.FLAG_ACTIVITY_NO_HISTORY
|
||||
import android.net.Uri
|
||||
import androidx.browser.customtabs.CustomTabColorSchemeParams
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
|
|
@ -36,9 +34,6 @@ internal class CustomTabsUrlOpener : UrlOpener {
|
|||
)
|
||||
.build()
|
||||
|
||||
// Open CustomTabsActivity as new task without saving into the stack
|
||||
customTabsIntent.intent.setFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_NO_HISTORY)
|
||||
|
||||
customTabsIntent.launchUrl(context, Uri.parse(url))
|
||||
}
|
||||
}
|
||||
|
|
@ -184,30 +184,6 @@ internal object SettingsDomainModule {
|
|||
return NeverToInitiallyAskPermissionUseCase(repository = permissionRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideIsFirstTimeAskingPermissionUseCase(
|
||||
permissionRepository: PermissionRepository,
|
||||
): IsFirstTimeAskingPermissionUseCase {
|
||||
return IsFirstTimeAskingPermissionUseCase(repository = permissionRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSetFirstTimeAskingPushPermissionUseCase(
|
||||
permissionRepository: PermissionRepository,
|
||||
): SetFirstTimeAskingPermissionUseCase {
|
||||
return SetFirstTimeAskingPermissionUseCase(repository = permissionRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideDelayPermissionRequestUseCase(
|
||||
permissionRepository: PermissionRepository,
|
||||
): DelayPermissionRequestUseCase {
|
||||
return DelayPermissionRequestUseCase(repository = permissionRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideShouldAskPermissionUseCase(permissionRepository: PermissionRepository): ShouldAskPermissionUseCase {
|
||||
|
|
|
|||
|
|
@ -161,6 +161,8 @@ internal class CardSettingsViewModel @Inject constructor(
|
|||
if (scanResponse.cardTypesResolver.isTangemTwins()) {
|
||||
store.dispatch(TwinCardsAction.SetMode(CreateTwinWalletMode.RecreateWallet(scanResponse)))
|
||||
|
||||
cardSettingsInteractor.clear()
|
||||
|
||||
store.dispatchNavigationAction { push(AppRoute.OnboardingTwins) }
|
||||
} else {
|
||||
val card = scanResponse.card
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@ import android.net.Uri
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface Disclaimer {
|
||||
fun type(): DisclaimerType
|
||||
fun getUri(): Uri
|
||||
suspend fun accept()
|
||||
suspend fun isAccepted(): Boolean
|
||||
}
|
||||
|
||||
abstract class BaseDisclaimer(
|
||||
protected val dataProvider: DisclaimerDataProvider,
|
||||
private val dataProvider: DisclaimerDataProvider,
|
||||
) : Disclaimer {
|
||||
|
||||
val baseUrl = "https://tangem.com"
|
||||
|
|
@ -26,46 +25,11 @@ abstract class BaseDisclaimer(
|
|||
}
|
||||
|
||||
class DummyDisclaimer : Disclaimer {
|
||||
override fun type(): DisclaimerType = DisclaimerType.Tangem
|
||||
override fun getUri(): Uri = Uri.parse("https://tangem.com/tangem_tos.html")
|
||||
override suspend fun accept() {}
|
||||
override suspend fun isAccepted(): Boolean = false
|
||||
}
|
||||
|
||||
class TangemDisclaimer(dataProvider: DisclaimerDataProvider) : BaseDisclaimer(dataProvider) {
|
||||
override fun type(): DisclaimerType = DisclaimerType.Tangem
|
||||
override fun getUri(): Uri = Uri.parse("$baseUrl/tangem_tos.html")
|
||||
}
|
||||
|
||||
class Start2CoinDisclaimer(dataProvider: DisclaimerDataProvider) : BaseDisclaimer(dataProvider) {
|
||||
override fun type(): DisclaimerType = DisclaimerType.Start2Coin
|
||||
override fun getUri(): Uri = Uri.parse("$baseUrl/" + filename(dataProvider.getLanguage(), getRegion()))
|
||||
|
||||
@Suppress("ComplexMethod")
|
||||
private fun filename(languageCode: String, regionCode: String?): String {
|
||||
return when {
|
||||
languageCode == "fr" && regionCode == "ch" -> "start2coin-fr-ch-tangem.html"
|
||||
languageCode == "de" && regionCode == "ch" -> "start2coin-de-ch-tangem.html"
|
||||
languageCode == "en" && regionCode == "ch" -> "start2coin-en-ch-tangem.html"
|
||||
languageCode == "it" && regionCode == "ch" -> "start2coin-it-ch-tangem.html"
|
||||
languageCode == "fr" && regionCode == "fr" -> "start2coin-fr-fr-tangem.html"
|
||||
languageCode == "de" && regionCode == "at" -> "start2coin-de-at-tangem.html"
|
||||
regionCode == "fr" -> "start2coin-fr-fr-tangem.html"
|
||||
regionCode == "ch" -> "start2coin-en-ch-tangem.html"
|
||||
regionCode == "at" -> "start2coin-de-at-tangem.html"
|
||||
else -> "start2coin-fr-fr-tangem.html"
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRegion(): String? {
|
||||
val cardId = dataProvider.getCardId()
|
||||
if (cardId.isEmpty()) return null
|
||||
|
||||
return when (cardId[1]) {
|
||||
'0' -> "fr"
|
||||
'1' -> "ch"
|
||||
'2' -> "at"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +1,28 @@
|
|||
package com.tangem.tap.features.disclaimer
|
||||
|
||||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
enum class DisclaimerType {
|
||||
Tangem,
|
||||
Start2Coin,
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun get(cardDTO: CardDTO): DisclaimerType {
|
||||
return when {
|
||||
cardDTO.isStart2Coin -> Start2Coin
|
||||
else -> Tangem
|
||||
}
|
||||
}
|
||||
}
|
||||
fun CardDTO.createDisclaimer(): Disclaimer {
|
||||
val dataProvider = provideDisclaimerDataProvider(cardId)
|
||||
return TangemDisclaimer(dataProvider)
|
||||
}
|
||||
|
||||
fun DisclaimerType.createDisclaimer(cardDTO: CardDTO): Disclaimer {
|
||||
val dataProvider = provideDisclaimerDataProvider(cardDTO.cardId, this)
|
||||
return when (this) {
|
||||
DisclaimerType.Tangem -> TangemDisclaimer(dataProvider)
|
||||
DisclaimerType.Start2Coin -> Start2CoinDisclaimer(dataProvider)
|
||||
}
|
||||
}
|
||||
|
||||
fun CardDTO.createDisclaimer(): Disclaimer = DisclaimerType.get(this).createDisclaimer(this)
|
||||
|
||||
private fun provideDisclaimerDataProvider(cardId: String, disclaimerType: DisclaimerType): DisclaimerDataProvider {
|
||||
private fun provideDisclaimerDataProvider(cardId: String): DisclaimerDataProvider {
|
||||
val cardRepository = store.inject(DaggerGraphState::cardRepository)
|
||||
return object : DisclaimerDataProvider {
|
||||
override fun getLanguage(): String = Locale.getDefault().language
|
||||
override fun getCardId(): String = cardId
|
||||
|
||||
override suspend fun accept() {
|
||||
when (disclaimerType) {
|
||||
DisclaimerType.Tangem -> cardRepository.acceptTangemTOS()
|
||||
DisclaimerType.Start2Coin -> cardRepository.acceptStart2CoinTOS(cardId)
|
||||
}
|
||||
cardRepository.acceptTangemTOS()
|
||||
}
|
||||
|
||||
override suspend fun isAccepted(): Boolean {
|
||||
return when (disclaimerType) {
|
||||
DisclaimerType.Tangem -> cardRepository.isTangemTOSAccepted()
|
||||
DisclaimerType.Start2Coin -> cardRepository.isStart2CoinTOSAccepted(cardId)
|
||||
}
|
||||
return cardRepository.isTangemTOSAccepted()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -65,9 +65,9 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager)
|
||||
|
||||
fun getScanResponse(): ScanResponse {
|
||||
return when (val mode = twinCardsState.mode) {
|
||||
return when (twinCardsState.mode) {
|
||||
is CreateTwinWalletMode.CreateWallet -> onboardingManager?.scanResponse
|
||||
is CreateTwinWalletMode.RecreateWallet -> mode.scanResponse
|
||||
is CreateTwinWalletMode.RecreateWallet -> globalState.scanResponse
|
||||
} ?: throw NullPointerException("ScanResponse can't be NULL")
|
||||
}
|
||||
|
||||
|
|
@ -105,6 +105,10 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
mainScope.launch {
|
||||
if (twinCardsState.currentStep is TwinCardsStep.WelcomeOnly) return@launch
|
||||
|
||||
if (twinCardsState.mode is CreateTwinWalletMode.RecreateWallet) {
|
||||
store.dispatch(GlobalAction.SaveScanResponse(twinCardsState.mode.scanResponse))
|
||||
}
|
||||
|
||||
val scanResponse = getScanResponse()
|
||||
onboardingManager?.apply {
|
||||
if (!isActivationStarted(scanResponse.card.cardId)) {
|
||||
|
|
@ -368,8 +372,7 @@ private fun getPopBackScreen(): KClass<out AppRoute> {
|
|||
val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager)
|
||||
|
||||
return if (userWalletsListManager.hasUserWallets) {
|
||||
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync }
|
||||
.fold(onSuccess = { true }, onFailure = { false })
|
||||
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync!! }.getOrElse { false }
|
||||
|
||||
if (isLocked) {
|
||||
AppRoute.Welcome::class
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import com.tangem.tap.features.onboarding.OnboardingDialog
|
|||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
|
|
@ -44,6 +45,8 @@ object OnboardingWalletMiddleware {
|
|||
val handler = onboardingWalletMiddleware
|
||||
}
|
||||
|
||||
private const val HIDE_PROGRESS_DELAY = 400L
|
||||
|
||||
private val onboardingWalletMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
|
|
@ -161,17 +164,13 @@ private fun handleWalletAction(action: Action) {
|
|||
store.dispatch(GlobalAction.Onboarding.Stop)
|
||||
|
||||
if (scanResponse == null) {
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
store.dispatch(HomeAction.ReadCard(scope = action.scope))
|
||||
action.scope.launch {
|
||||
readCard { newScanResponse ->
|
||||
handleFinishOnboardind(newScanResponse)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val backupState = store.state.onboardingWalletState.backupState
|
||||
val updatedScanResponse = updateScanResponseAfterBackup(scanResponse, backupState)
|
||||
OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(
|
||||
scanResponse = updatedScanResponse,
|
||||
accessCode = backupState.accessCode,
|
||||
backupCardsIds = backupState.backupCardIds,
|
||||
hasBackupError = backupState.hasBackupError,
|
||||
)
|
||||
handleFinishOnboardind(scanResponse)
|
||||
}
|
||||
}
|
||||
is OnboardingWalletAction.ResumeBackup -> {
|
||||
|
|
@ -196,6 +195,43 @@ private fun handleWalletAction(action: Action) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleFinishOnboardind(scanResponse: ScanResponse) {
|
||||
val backupState = store.state.onboardingWalletState.backupState
|
||||
val updatedScanResponse = updateScanResponseAfterBackup(scanResponse, backupState)
|
||||
OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(
|
||||
scanResponse = updatedScanResponse,
|
||||
accessCode = backupState.accessCode,
|
||||
backupCardsIds = backupState.backupCardIds,
|
||||
hasBackupError = backupState.hasBackupError,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun readCard(onSuccess: (ScanResponse) -> Unit) {
|
||||
val shouldSaveAccessCodes = store.inject(DaggerGraphState::settingsRepository).shouldSaveAccessCodes()
|
||||
|
||||
store.inject(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = shouldSaveAccessCodes,
|
||||
)
|
||||
|
||||
store.inject(DaggerGraphState::scanCardProcessor).scan(
|
||||
analyticsSource = com.tangem.core.analytics.models.AnalyticsParam.ScreensSources.Intro,
|
||||
onProgressStateChange = { showProgress ->
|
||||
if (showProgress) {
|
||||
store.dispatch(HomeAction.ScanInProgress(scanInProgress = true))
|
||||
} else {
|
||||
delay(HIDE_PROGRESS_DELAY)
|
||||
store.dispatch(HomeAction.ScanInProgress(scanInProgress = false))
|
||||
}
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Unable to scan card")
|
||||
delay(HIDE_PROGRESS_DELAY)
|
||||
store.dispatch(HomeAction.ScanInProgress(scanInProgress = false))
|
||||
},
|
||||
onSuccess = onSuccess,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun loadArtworkForUnfinishedBackup(
|
||||
cardId: String,
|
||||
cardPublicKey: ByteArray,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ import androidx.compose.animation.AnimatedVisibility
|
|||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Text
|
||||
|
|
@ -123,14 +126,14 @@ internal fun HasMoreItem(moreCount: Int) {
|
|||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(TangemTheme.dimens.spacing4)
|
||||
.align(Alignment.Center)
|
||||
.drawWithContent { if (readyToDraw) drawContent() },
|
||||
text = "+$count",
|
||||
style = textStyle,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
overflow = TextOverflow.Clip,
|
||||
onTextLayout = { textLayoutResult ->
|
||||
if (textLayoutResult.didOverflowHeight) {
|
||||
if (textLayoutResult.hasVisualOverflow) {
|
||||
textStyle = textStyle.copy(fontSize = textStyle.fontSize * 0.9)
|
||||
} else {
|
||||
readyToDraw = true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue