Updated on 2026-08-14
This commit is contained in:
parent
587a0c8624
commit
88cf7ec1af
212 changed files with 1223 additions and 1128 deletions
33
.idea/codeStyles/Project.xml
generated
33
.idea/codeStyles/Project.xml
generated
|
|
@ -5,6 +5,39 @@
|
||||||
<JavaCodeStyleSettings>
|
<JavaCodeStyleSettings>
|
||||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="5" />
|
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="5" />
|
||||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="3" />
|
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="3" />
|
||||||
|
<option name="IMPORT_LAYOUT_TABLE">
|
||||||
|
<value>
|
||||||
|
<package name="" withSubpackages="true" static="false" module="true" />
|
||||||
|
<package name="android" withSubpackages="true" static="true" />
|
||||||
|
<package name="androidx" withSubpackages="true" static="true" />
|
||||||
|
<package name="com" withSubpackages="true" static="true" />
|
||||||
|
<package name="junit" withSubpackages="true" static="true" />
|
||||||
|
<package name="net" withSubpackages="true" static="true" />
|
||||||
|
<package name="org" withSubpackages="true" static="true" />
|
||||||
|
<package name="java" withSubpackages="true" static="true" />
|
||||||
|
<package name="javax" withSubpackages="true" static="true" />
|
||||||
|
<package name="" withSubpackages="true" static="true" />
|
||||||
|
<emptyLine />
|
||||||
|
<package name="android" withSubpackages="true" static="false" />
|
||||||
|
<emptyLine />
|
||||||
|
<package name="androidx" withSubpackages="true" static="false" />
|
||||||
|
<emptyLine />
|
||||||
|
<package name="com" withSubpackages="true" static="false" />
|
||||||
|
<emptyLine />
|
||||||
|
<package name="junit" withSubpackages="true" static="false" />
|
||||||
|
<emptyLine />
|
||||||
|
<package name="net" withSubpackages="true" static="false" />
|
||||||
|
<emptyLine />
|
||||||
|
<package name="org" withSubpackages="true" static="false" />
|
||||||
|
<emptyLine />
|
||||||
|
<package name="java" withSubpackages="true" static="false" />
|
||||||
|
<emptyLine />
|
||||||
|
<package name="javax" withSubpackages="true" static="false" />
|
||||||
|
<emptyLine />
|
||||||
|
<package name="" withSubpackages="true" static="false" />
|
||||||
|
<emptyLine />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
</JavaCodeStyleSettings>
|
</JavaCodeStyleSettings>
|
||||||
<JetCodeStyleSettings>
|
<JetCodeStyleSettings>
|
||||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
tangemSdkManager = injectedTangemSdkManager
|
tangemSdkManager = injectedTangemSdkManager
|
||||||
|
|
||||||
backupServiceHolder.createAndSetService(cardSdkConfigRepository.sdk, this)
|
backupServiceHolder.createAndSetService(cardSdkConfigRepository.sdk, this)
|
||||||
backupService = backupServiceHolder.backupService.get()!! // will be deleted eventually
|
backupService = requireNotNull(backupServiceHolder.backupService.get()) // will be deleted eventually
|
||||||
|
|
||||||
lockUserWalletsTimer = LockUserWalletsTimer(
|
lockUserWalletsTimer = LockUserWalletsTimer(
|
||||||
context = this,
|
context = this,
|
||||||
|
|
@ -370,8 +370,8 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
override fun onNewIntent(intent: Intent?) {
|
override fun onNewIntent(intent: Intent?) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
|
|
||||||
val fromPush = intent?.extras?.containsKey(OPENED_FROM_GCM_PUSH) ?: false
|
val isFromPush = intent?.extras?.containsKey(OPENED_FROM_GCM_PUSH) == true
|
||||||
if (fromPush) {
|
if (isFromPush) {
|
||||||
analyticsEventsHandler.send(Push.PushNotificationOpened)
|
analyticsEventsHandler.send(Push.PushNotificationOpened)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -402,8 +402,8 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
||||||
val result = WindowObscurationObserver.dispatchTouchEvent(event, analyticsEventsHandler)
|
val isHandled = WindowObscurationObserver.dispatchTouchEvent(event, analyticsEventsHandler)
|
||||||
return if (result) super.dispatchTouchEvent(event) else false
|
return if (isHandled) super.dispatchTouchEvent(event) else false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||||
|
|
@ -447,9 +447,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
||||||
getPolkadotCheckHasImmortalUseCase()
|
getPolkadotCheckHasImmortalUseCase()
|
||||||
.flowWithLifecycle(lifecycle, minActiveState = Lifecycle.State.CREATED)
|
.flowWithLifecycle(lifecycle, minActiveState = Lifecycle.State.CREATED)
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.collect {
|
.collect { (_, hasImmortalTransaction) ->
|
||||||
analyticsEventsHandler.send(
|
analyticsEventsHandler.send(
|
||||||
WalletScreenAnalyticsEvent.Token.PolkadotImmortalTransactions(it.second),
|
WalletScreenAnalyticsEvent.Token.PolkadotImmortalTransactions(hasImmortalTransaction),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ lateinit var store: Store<AppState>
|
||||||
lateinit var foregroundActivityObserver: ForegroundActivityObserver
|
lateinit var foregroundActivityObserver: ForegroundActivityObserver
|
||||||
internal lateinit var derivationsFinder: DerivationsFinder
|
internal lateinit var derivationsFinder: DerivationsFinder
|
||||||
|
|
||||||
abstract class TangemApplication : Application(), ImageLoaderFactory, Configuration.Provider {
|
open class TangemApplication : Application(), ImageLoaderFactory, Configuration.Provider {
|
||||||
|
|
||||||
// region DI
|
// region DI
|
||||||
private val entryPoint: ApplicationEntryPoint
|
private val entryPoint: ApplicationEntryPoint
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ package com.tangem.tap.common
|
||||||
object TestActions {
|
object TestActions {
|
||||||
|
|
||||||
// It used only for the test actions in debug or debug_beta builds
|
// It used only for the test actions in debug or debug_beta builds
|
||||||
var testAmountInjectionForWalletManagerEnabled = false
|
var isTestAmountInjectionForWalletManagerEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias TestAction = Pair<String, () -> Unit>
|
typealias TestAction = Pair<String, () -> Unit>
|
||||||
|
|
@ -58,7 +58,7 @@ private class BlockchainSdkErrorConverter(
|
||||||
if (value.customMessage.contains(DemoTransactionSender.ID)) return emptyMap()
|
if (value.customMessage.contains(DemoTransactionSender.ID)) return emptyMap()
|
||||||
|
|
||||||
if (value is BlockchainSdkError.WrappedTangemError) {
|
if (value is BlockchainSdkError.WrappedTangemError) {
|
||||||
return (value.tangemError as? TangemSdkError)?.let { cardSdkErrorConverter.convert(it) } ?: emptyMap()
|
return (value.tangemError as? TangemSdkError)?.let { cardSdkErrorConverter.convert(it) }.orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapOf(
|
return mapOf(
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
|
||||||
*/
|
*/
|
||||||
sealed class Chat(
|
sealed class Chat(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent("Chat", event, params) {
|
) : AnalyticsEvent("Chat", event, params) {
|
||||||
|
|
||||||
class ScreenOpened : Chat("Chat Screen Opened")
|
class ScreenOpened : Chat("Chat Screen Opened")
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
|
||||||
sealed class Onboarding(
|
sealed class Onboarding(
|
||||||
category: String,
|
category: String,
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent(category, event, params) {
|
) : AnalyticsEvent(category, event, params) {
|
||||||
|
|
||||||
class Started : Onboarding("Onboarding", "Onboarding Started")
|
class Started : Onboarding("Onboarding", "Onboarding Started")
|
||||||
|
|
@ -16,7 +16,7 @@ sealed class Onboarding(
|
||||||
|
|
||||||
sealed class CreateWallet(
|
sealed class CreateWallet(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : Onboarding("Onboarding / Create Wallet", event, params) {
|
) : Onboarding("Onboarding / Create Wallet", event, params) {
|
||||||
|
|
||||||
class ScreenOpened : CreateWallet("Create Wallet Screen Opened")
|
class ScreenOpened : CreateWallet("Create Wallet Screen Opened")
|
||||||
|
|
@ -36,7 +36,7 @@ sealed class Onboarding(
|
||||||
|
|
||||||
sealed class Backup(
|
sealed class Backup(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : Onboarding("Onboarding / Backup", event, params) {
|
) : Onboarding("Onboarding / Backup", event, params) {
|
||||||
|
|
||||||
class ScreenOpened : Backup("Backup Screen Opened")
|
class ScreenOpened : Backup("Backup Screen Opened")
|
||||||
|
|
@ -64,7 +64,7 @@ sealed class Onboarding(
|
||||||
|
|
||||||
sealed class Topup(
|
sealed class Topup(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : Onboarding("Onboarding / Top Up", event, params) {
|
) : Onboarding("Onboarding / Top Up", event, params) {
|
||||||
|
|
||||||
class ScreenOpened : Topup("Activation Screen Opened")
|
class ScreenOpened : Topup("Activation Screen Opened")
|
||||||
|
|
@ -79,7 +79,7 @@ sealed class Onboarding(
|
||||||
|
|
||||||
sealed class Twins(
|
sealed class Twins(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : Onboarding("Onboarding / Twins", event, params) {
|
) : Onboarding("Onboarding / Twins", event, params) {
|
||||||
|
|
||||||
class ScreenOpened : Twins("Twinning Screen Opened")
|
class ScreenOpened : Twins("Twinning Screen Opened")
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
|
||||||
sealed class Settings(
|
sealed class Settings(
|
||||||
category: String = "Settings",
|
category: String = "Settings",
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent(category, event, params) {
|
) : AnalyticsEvent(category, event, params) {
|
||||||
|
|
||||||
class ScreenOpened : Settings(event = "Settings Screen Opened")
|
class ScreenOpened : Settings(event = "Settings Screen Opened")
|
||||||
|
|
@ -17,7 +17,7 @@ sealed class Settings(
|
||||||
|
|
||||||
sealed class CardSettings(
|
sealed class CardSettings(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : Settings("Settings / Card Settings", event, params) {
|
) : Settings("Settings / Card Settings", event, params) {
|
||||||
|
|
||||||
class ButtonFactoryReset : CardSettings("Button - Factory Reset")
|
class ButtonFactoryReset : CardSettings("Button - Factory Reset")
|
||||||
|
|
@ -54,7 +54,7 @@ sealed class Settings(
|
||||||
|
|
||||||
sealed class AppSettings(
|
sealed class AppSettings(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : Settings(category = "Settings / App Settings", event = event, params = params) {
|
) : Settings(category = "Settings / App Settings", event = event, params = params) {
|
||||||
|
|
||||||
class SaveWalletSwitcherChanged(state: AnalyticsParam.OnOffState) : AppSettings(
|
class SaveWalletSwitcherChanged(state: AnalyticsParam.OnOffState) : AppSettings(
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
|
||||||
*/
|
*/
|
||||||
sealed class SignIn(
|
sealed class SignIn(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent("Sign In", event, params) {
|
) : AnalyticsEvent("Sign In", event, params) {
|
||||||
|
|
||||||
class ScreenOpened : SignIn(event = "Sign In Screen Opened")
|
class ScreenOpened : SignIn(event = "Sign In Screen Opened")
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
|
||||||
sealed class Token(
|
sealed class Token(
|
||||||
category: String,
|
category: String,
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent(category, event, params) {
|
) : AnalyticsEvent(category, event, params) {
|
||||||
|
|
||||||
sealed class Receive(
|
sealed class Receive(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : Token("Token / Receive", event, params) {
|
) : Token("Token / Receive", event, params) {
|
||||||
|
|
||||||
class ScreenOpened(
|
class ScreenOpened(
|
||||||
|
|
@ -29,7 +29,7 @@ sealed class Token(
|
||||||
|
|
||||||
sealed class Topup(
|
sealed class Topup(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : Token("Token / Topup", event, params) {
|
) : Token("Token / Topup", event, params) {
|
||||||
|
|
||||||
class ScreenOpened : Topup("Top Up Screen Opened")
|
class ScreenOpened : Topup("Top Up Screen Opened")
|
||||||
|
|
@ -38,7 +38,7 @@ sealed class Token(
|
||||||
|
|
||||||
sealed class Withdraw(
|
sealed class Withdraw(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : Token("Token / Withdraw", event, params) {
|
) : Token("Token / Withdraw", event, params) {
|
||||||
|
|
||||||
class ScreenOpened : Withdraw("Withdraw Screen Opened")
|
class ScreenOpened : Withdraw("Withdraw Screen Opened")
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ internal class DefaultClipboardManager(private val clipboardManager: AndroidClip
|
||||||
clipboardManager.setPrimaryClip(clip)
|
clipboardManager.setPrimaryClip(clip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UseIsNullOrEmpty")
|
||||||
override fun getText(default: String?): String? {
|
override fun getText(default: String?): String? {
|
||||||
val clip = clipboardManager.primaryClip
|
val clip = clipboardManager.primaryClip
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,6 @@ fun Store<AppState>.dispatchNavigationAction(action: AppRouter.() -> Unit) {
|
||||||
|
|
||||||
inline fun <reified T> Store<AppState>.inject(getDependency: DaggerGraphState.() -> T?): T {
|
inline fun <reified T> Store<AppState>.inject(getDependency: DaggerGraphState.() -> T?): T {
|
||||||
return requireNotNull(state.daggerGraphState.getDependency()) {
|
return requireNotNull(state.daggerGraphState.getDependency()) {
|
||||||
"${T::class.simpleName} isn't initialized "
|
"${T::class.simpleName.orEmpty()} isn't initialized "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -22,9 +22,9 @@ import timber.log.Timber
|
||||||
)
|
)
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
suspend fun WalletManager.safeUpdate(isDemoCard: Boolean): Result<Wallet> = try {
|
suspend fun WalletManager.safeUpdate(isDemoCard: Boolean): Result<Wallet> = try {
|
||||||
if (isDemoCard || TestActions.testAmountInjectionForWalletManagerEnabled) {
|
if (isDemoCard || TestActions.isTestAmountInjectionForWalletManagerEnabled) {
|
||||||
delay(500)
|
delay(500)
|
||||||
TestActions.testAmountInjectionForWalletManagerEnabled = false
|
TestActions.isTestAmountInjectionForWalletManagerEnabled = false
|
||||||
Result.Success(wallet)
|
Result.Success(wallet)
|
||||||
} else {
|
} else {
|
||||||
update()
|
update()
|
||||||
|
|
@ -35,7 +35,7 @@ suspend fun WalletManager.safeUpdate(isDemoCard: Boolean): Result<Wallet> = try
|
||||||
|
|
||||||
val networkConnectionManager = store.inject(DaggerGraphState::networkConnectionManager)
|
val networkConnectionManager = store.inject(DaggerGraphState::networkConnectionManager)
|
||||||
if (!networkConnectionManager.isOnline) {
|
if (!networkConnectionManager.isOnline) {
|
||||||
Result.Failure(TapError.NoInternetConnection)
|
Result.Failure(TapError.NoInternetConnection())
|
||||||
} else {
|
} else {
|
||||||
val blockchain = wallet.blockchain
|
val blockchain = wallet.blockchain
|
||||||
val amountToCreateAccount = blockchain.amountToCreateAccount(this, wallet.getFirstToken())
|
val amountToCreateAccount = blockchain.amountToCreateAccount(this, wallet.getFirstToken())
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ class TangemAppLoggerInitializer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("BooleanPropertyNaming")
|
||||||
private companion object {
|
private companion object {
|
||||||
val IS_LOG_ENABLED: Boolean = BuildConfig.LOG_ENABLED
|
val IS_LOG_ENABLED: Boolean = BuildConfig.LOG_ENABLED
|
||||||
val PERMITTED_PRIORITY = listOf(Log.ERROR, Log.INFO)
|
val PERMITTED_PRIORITY = listOf(Log.ERROR, Log.INFO)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,6 @@ data class GlobalState(
|
||||||
typealias CryptoCurrencyName = String
|
typealias CryptoCurrencyName = String
|
||||||
|
|
||||||
data class OnboardingState(
|
data class OnboardingState(
|
||||||
val onboardingStarted: Boolean = false,
|
val isOnboardingStarted: Boolean = false,
|
||||||
val shouldResetOnCreate: Boolean = false,
|
val shouldResetOnCreate: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
@ -61,9 +61,9 @@ internal class AndroidEmailSender : EmailSender {
|
||||||
.setSubject(email.subject)
|
.setSubject(email.subject)
|
||||||
.setText(email.message)
|
.setText(email.message)
|
||||||
|
|
||||||
email.attachment?.let {
|
email.attachment?.let { file ->
|
||||||
builder.setStream(
|
builder.setStream(
|
||||||
FileProvider.getUriForFile(activity, "${activity.packageName}.provider", it),
|
FileProvider.getUriForFile(activity, "${activity.packageName}.provider", file),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class TangemSigner(
|
||||||
TangemSignerResponse(
|
TangemSignerResponse(
|
||||||
totalSignedHashes = result.data.totalSignedHashes,
|
totalSignedHashes = result.data.totalSignedHashes,
|
||||||
remainingSignatures = result.data.remainingSignatures,
|
remainingSignatures = result.data.remainingSignatures,
|
||||||
isRing = result.data.batchId?.let(::isRing) ?: false,
|
isRing = result.data.batchId?.let(::isRing) == true,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if (continuation.isActive) {
|
if (continuation.isActive) {
|
||||||
|
|
@ -85,7 +85,7 @@ class TangemSigner(
|
||||||
TangemSignerResponse(
|
TangemSignerResponse(
|
||||||
totalSignedHashes = result.data.totalSignedHashes,
|
totalSignedHashes = result.data.totalSignedHashes,
|
||||||
remainingSignatures = result.data.remainingSignatures,
|
remainingSignatures = result.data.remainingSignatures,
|
||||||
isRing = result.data.batchId?.let(::isRing) ?: false,
|
isRing = result.data.batchId?.let(::isRing) == true,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if (continuation.isActive) {
|
if (continuation.isActive) {
|
||||||
|
|
|
||||||
|
|
@ -20,23 +20,23 @@ sealed class TapError(
|
||||||
override val args: List<Any>? = null,
|
override val args: List<Any>? = null,
|
||||||
) : Throwable(), TapErrors, ArgError {
|
) : Throwable(), TapErrors, ArgError {
|
||||||
|
|
||||||
object UnknownError : TapError(R.string.send_error_unknown)
|
class UnknownError : TapError(R.string.send_error_unknown)
|
||||||
open class CustomError(val customMessage: String) : TapError(R.string.common_custom_string, listOf(customMessage))
|
open class CustomError(val customMessage: String) : TapError(R.string.common_custom_string, listOf(customMessage))
|
||||||
|
|
||||||
object NoInternetConnection : TapError(R.string.wallet_notification_no_internet)
|
class NoInternetConnection : TapError(R.string.wallet_notification_no_internet)
|
||||||
|
|
||||||
sealed class WalletManager {
|
sealed class WalletManager {
|
||||||
class NoAccountError(amountToCreateAccount: String) : CustomError(amountToCreateAccount)
|
class NoAccountError(amountToCreateAccount: String) : CustomError(amountToCreateAccount)
|
||||||
class InternalError(message: String) : CustomError(message)
|
class InternalError(message: String) : CustomError(message)
|
||||||
object BlockchainIsUnreachableTryLater : TapError(R.string.wallet_balance_blockchain_unreachable_try_later)
|
class BlockchainIsUnreachableTryLater : TapError(R.string.wallet_balance_blockchain_unreachable_try_later)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class TapSdkError(override val messageResId: Int?) : TangemError(code = 50100) {
|
sealed class TapSdkError(override val messageResId: Int?) : TangemError(code = 50100) {
|
||||||
override var customMessage: String = code.toString()
|
override var customMessage: String = code.toString()
|
||||||
|
|
||||||
object CardForDifferentApp : TapSdkError(R.string.alert_unsupported_card)
|
class CardForDifferentApp : TapSdkError(R.string.alert_unsupported_card)
|
||||||
object CardNotSupportedByRelease : TapSdkError(R.string.error_wrong_card_type)
|
class CardNotSupportedByRelease : TapSdkError(R.string.error_wrong_card_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TapErrors.assembleErrors(): MutableList<Pair<Int, List<Any>?>> {
|
fun TapErrors.assembleErrors(): MutableList<Pair<Int, List<Any>?>> {
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ internal class DefaultResetCardUseCase(
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
type?.let {
|
if (type != null) {
|
||||||
tangemSdkManager.setUserCodeRequestPolicy(policy = UserCodeRequestPolicy.Always(type))
|
tangemSdkManager.setUserCodeRequestPolicy(policy = UserCodeRequestPolicy.Always(type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,14 +119,14 @@ internal class LegacyScanProcessor @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendAnalytics(analyticsEvent: AnalyticsEvent?, scanResponse: ScanResponse) {
|
private fun sendAnalytics(analyticsEvent: AnalyticsEvent?, scanResponse: ScanResponse) {
|
||||||
analyticsEvent?.let {
|
analyticsEvent?.let { event ->
|
||||||
// this workaround needed to send CardWasScannedEvent without adding a context
|
// this workaround needed to send CardWasScannedEvent without adding a context
|
||||||
val interceptor = CardContextInterceptor(scanResponse)
|
val interceptor = CardContextInterceptor(scanResponse)
|
||||||
val params = it.params.toMutableMap()
|
val params = event.params.toMutableMap()
|
||||||
interceptor.intercept(params)
|
interceptor.intercept(params)
|
||||||
it.params = params.toMap()
|
event.params = params.toMap()
|
||||||
|
|
||||||
Analytics.send(it)
|
Analytics.send(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ internal object UseCaseScanProcessor {
|
||||||
|
|
||||||
return scanCardUseCase(cardId, allowsRequestAccessCodeFromRepository)
|
return scanCardUseCase(cardId, allowsRequestAccessCodeFromRepository)
|
||||||
.fold(
|
.fold(
|
||||||
ifLeft = {
|
ifLeft = { scanCardException ->
|
||||||
val error = scanCardExceptionConverter.convertBack(it)
|
val error = scanCardExceptionConverter.convertBack(scanCardException)
|
||||||
|
|
||||||
Analytics.sendErrorEvent(TangemSdkErrorEvent(error))
|
Analytics.sendErrorEvent(TangemSdkErrorEvent(error))
|
||||||
CompletionResult.Failure(error)
|
CompletionResult.Failure(error)
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ sealed class ScanChainException : ScanCardException.ChainException() {
|
||||||
/**
|
/**
|
||||||
* May be returned from [DisclaimerChain]
|
* May be returned from [DisclaimerChain]
|
||||||
* */
|
* */
|
||||||
data object DisclaimerWasCanceled : ScanChainException() {
|
class DisclaimerWasCanceled : ScanChainException() {
|
||||||
|
|
||||||
@Suppress("UnusedPrivateMember")
|
@Suppress("UnusedPrivateMember")
|
||||||
private fun readResolve(): Any = DisclaimerWasCanceled
|
private fun readResolve(): Any = DisclaimerWasCanceled()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -13,19 +13,19 @@ object MockProvider {
|
||||||
|
|
||||||
private var content: MockContent = getMockContent(ProductType.Wallet)
|
private var content: MockContent = getMockContent(ProductType.Wallet)
|
||||||
|
|
||||||
private var emulateError: Boolean = false
|
private var isEmulatingError: Boolean = false
|
||||||
|
|
||||||
private var emulatedError: TangemError = TangemSdkError.TagLost()
|
private var emulatedError: TangemError = TangemSdkError.TagLost()
|
||||||
|
|
||||||
fun setEmulateError(error: TangemError? = null) {
|
fun setEmulateError(error: TangemError? = null) {
|
||||||
emulateError = true
|
isEmulatingError = true
|
||||||
error?.let {
|
error?.let {
|
||||||
emulatedError = it
|
emulatedError = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetEmulateError() {
|
fun resetEmulateError() {
|
||||||
emulateError = false
|
isEmulatingError = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setMocks(productType: ProductType) {
|
fun setMocks(productType: ProductType) {
|
||||||
|
|
@ -74,7 +74,7 @@ object MockProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T> CompletionResult.Success<T>.orFailure(): CompletionResult<T> {
|
private fun <T> CompletionResult.Success<T>.orFailure(): CompletionResult<T> {
|
||||||
return if (emulateError) {
|
return if (isEmulatingError) {
|
||||||
CompletionResult.Failure(emulatedError)
|
CompletionResult.Failure(emulatedError)
|
||||||
} else {
|
} else {
|
||||||
this
|
this
|
||||||
|
|
|
||||||
|
|
@ -168,52 +168,52 @@ object BackupWalletMockContent : MockContent {
|
||||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||||
)
|
)
|
||||||
to
|
to
|
||||||
ExtendedPublicKeysMap(
|
ExtendedPublicKeysMap(
|
||||||
mapOf(
|
mapOf(
|
||||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey(
|
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey(
|
||||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -234,24 +234,24 @@ object BackupWalletMockContent : MockContent {
|
||||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||||
)
|
)
|
||||||
to
|
to
|
||||||
ExtendedPublicKeysMap(
|
ExtendedPublicKeysMap(
|
||||||
mapOf(
|
mapOf(
|
||||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
primaryCard = primaryCard,
|
primaryCard = primaryCard,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -168,52 +168,52 @@ object DevWalletMockContent : MockContent {
|
||||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||||
)
|
)
|
||||||
to
|
to
|
||||||
ExtendedPublicKeysMap(
|
ExtendedPublicKeysMap(
|
||||||
mapOf(
|
mapOf(
|
||||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey(
|
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey(
|
||||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -234,24 +234,24 @@ object DevWalletMockContent : MockContent {
|
||||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||||
)
|
)
|
||||||
to
|
to
|
||||||
ExtendedPublicKeysMap(
|
ExtendedPublicKeysMap(
|
||||||
mapOf(
|
mapOf(
|
||||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
primaryCard = primaryCard,
|
primaryCard = primaryCard,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -219,38 +219,38 @@ object Wallet2MockContent : MockContent {
|
||||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||||
)
|
)
|
||||||
to
|
to
|
||||||
ExtendedPublicKeysMap(
|
ExtendedPublicKeysMap(
|
||||||
mapOf(
|
mapOf(
|
||||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -271,24 +271,24 @@ object Wallet2MockContent : MockContent {
|
||||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||||
)
|
)
|
||||||
to
|
to
|
||||||
ExtendedPublicKeysMap(
|
ExtendedPublicKeysMap(
|
||||||
mapOf(
|
mapOf(
|
||||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
primaryCard = primaryCard,
|
primaryCard = primaryCard,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -219,38 +219,38 @@ object Wallet2WithSeedPhraseMockContent : MockContent {
|
||||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||||
)
|
)
|
||||||
to
|
to
|
||||||
ExtendedPublicKeysMap(
|
ExtendedPublicKeysMap(
|
||||||
mapOf(
|
mapOf(
|
||||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -271,24 +271,24 @@ object Wallet2WithSeedPhraseMockContent : MockContent {
|
||||||
byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||||
)
|
)
|
||||||
to
|
to
|
||||||
ExtendedPublicKeysMap(
|
ExtendedPublicKeysMap(
|
||||||
mapOf(
|
mapOf(
|
||||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
primaryCard = primaryCard,
|
primaryCard = primaryCard,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -168,59 +168,59 @@ object WalletMockContent : MockContent {
|
||||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||||
)
|
)
|
||||||
to
|
to
|
||||||
ExtendedPublicKeysMap(
|
ExtendedPublicKeysMap(
|
||||||
mapOf(
|
mapOf(
|
||||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/144'/0'/0/0") to ExtendedPublicKey( // xrp
|
DerivationPath("m/44'/144'/0'/0/0") to ExtendedPublicKey( // xrp
|
||||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey(
|
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey(
|
||||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -241,24 +241,24 @@ object WalletMockContent : MockContent {
|
||||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||||
)
|
)
|
||||||
to
|
to
|
||||||
ExtendedPublicKeysMap(
|
ExtendedPublicKeysMap(
|
||||||
mapOf(
|
mapOf(
|
||||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
),
|
||||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||||
depth = 0,
|
depth = 0,
|
||||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||||
childNumber = 0,
|
childNumber = 0,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
primaryCard = primaryCard,
|
primaryCard = primaryCard,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,12 @@ class SignHashesTask(
|
||||||
is CompletionResult.Failure -> {
|
is CompletionResult.Failure -> {
|
||||||
when {
|
when {
|
||||||
response.error is TangemSdkError.WalletNotFound && pairWalletPublicKey != null -> {
|
response.error is TangemSdkError.WalletNotFound && pairWalletPublicKey != null -> {
|
||||||
sign(session, pairWalletPublicKey, publicKey.derivationPath, callback)
|
sign(
|
||||||
|
session = session,
|
||||||
|
publicKey = pairWalletPublicKey,
|
||||||
|
derivationPath = publicKey.derivationPath,
|
||||||
|
callback = callback,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
else -> callback(CompletionResult.Failure(response.error))
|
else -> callback(CompletionResult.Failure(response.error))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,22 +64,28 @@ class CreateProductWalletTask(
|
||||||
cardTypesResolver.isTangemTwins() ->
|
cardTypesResolver.isTangemTwins() ->
|
||||||
throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
|
throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
|
||||||
|
|
||||||
else -> CreateWalletTangemWallet(mnemonic, passphrase, shouldReset, derivationStyleProvider, cardDto)
|
else -> CreateWalletTangemWallet(
|
||||||
|
mnemonic = mnemonic,
|
||||||
|
passphrase = passphrase,
|
||||||
|
shouldReset = shouldReset,
|
||||||
|
derivationStyleProvider = derivationStyleProvider,
|
||||||
|
cardDTO = cardDto,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
commandProcessor.proceed(cardDto, session) {
|
commandProcessor.proceed(cardDto, session) { result ->
|
||||||
when (it) {
|
when (result) {
|
||||||
is CompletionResult.Success -> {
|
is CompletionResult.Success -> {
|
||||||
val result = when (commandProcessor) {
|
val createProductWalletTaskResponse = when (commandProcessor) {
|
||||||
is CreateWalletTangemWallet -> {
|
is CreateWalletTangemWallet -> {
|
||||||
it.data as CreateProductWalletTaskResponse
|
result.data as CreateProductWalletTaskResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> CreateProductWalletTaskResponse(card = session.environment.card!!)
|
else -> CreateProductWalletTaskResponse(card = requireNotNull(session.environment.card))
|
||||||
}
|
}
|
||||||
callback(CompletionResult.Success(result))
|
callback(CompletionResult.Success(createProductWalletTaskResponse))
|
||||||
}
|
}
|
||||||
|
|
||||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(it.error))
|
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +162,12 @@ private class CreateWalletTangemWallet(
|
||||||
CreateWalletsTask(cardConfig.mandatoryCurves, mnemonic, passphrase).run(session) { result ->
|
CreateWalletsTask(cardConfig.mandatoryCurves, mnemonic, passphrase).run(session) { result ->
|
||||||
when (result) {
|
when (result) {
|
||||||
is CompletionResult.Success -> {
|
is CompletionResult.Success -> {
|
||||||
checkIfAllWalletsCreated(card, session, result.data, callback)
|
checkIfAllWalletsCreated(
|
||||||
|
card = card,
|
||||||
|
session = session,
|
||||||
|
createResponse = result.data,
|
||||||
|
callback = callback,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is CompletionResult.Failure -> {
|
is CompletionResult.Failure -> {
|
||||||
callback(CompletionResult.Failure(result.error))
|
callback(CompletionResult.Failure(result.error))
|
||||||
|
|
@ -210,12 +221,16 @@ private class CreateWalletTangemWallet(
|
||||||
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
|
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
|
||||||
) {
|
) {
|
||||||
val resetCommand = ResetToFactorySettingsTask(allowsRequestAccessCodeFromRepository = false)
|
val resetCommand = ResetToFactorySettingsTask(allowsRequestAccessCodeFromRepository = false)
|
||||||
resetCommand.run(session) {
|
resetCommand.run(session) { result ->
|
||||||
when (it) {
|
when (result) {
|
||||||
is CompletionResult.Success -> {
|
is CompletionResult.Success -> {
|
||||||
createMultiWallet(card, session, callback)
|
createMultiWallet(
|
||||||
|
card = card,
|
||||||
|
session = session,
|
||||||
|
callback = callback,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(it.error))
|
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -228,17 +243,27 @@ private class CreateWalletTangemWallet(
|
||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
card.settings.isBackupAllowed -> {
|
card.settings.isBackupAllowed -> {
|
||||||
linkPrimaryCard(card, createWalletResponses, session, callback)
|
linkPrimaryCard(
|
||||||
|
card = card,
|
||||||
|
createWalletResponses = createWalletResponses,
|
||||||
|
session = session,
|
||||||
|
callback = callback,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
card.settings.isHDWalletAllowed -> {
|
card.settings.isHDWalletAllowed -> {
|
||||||
deriveKeys(card, createWalletResponses, session, callback)
|
deriveKeys(
|
||||||
|
card = card,
|
||||||
|
createWalletResponses = createWalletResponses,
|
||||||
|
session = session,
|
||||||
|
callback = callback,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
callback(
|
callback(
|
||||||
CompletionResult.Success(
|
CompletionResult.Success(
|
||||||
CreateProductWalletTaskResponse(card = session.environment.card!!),
|
CreateProductWalletTaskResponse(card = requireNotNull(session.environment.card)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -247,7 +272,7 @@ private class CreateWalletTangemWallet(
|
||||||
|
|
||||||
private fun linkPrimaryCard(
|
private fun linkPrimaryCard(
|
||||||
card: CardDTO,
|
card: CardDTO,
|
||||||
createWalletResponse: List<CreateWalletResponse>,
|
createWalletResponses: List<CreateWalletResponse>,
|
||||||
session: CardSession,
|
session: CardSession,
|
||||||
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
|
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
|
||||||
) {
|
) {
|
||||||
|
|
@ -257,14 +282,19 @@ private class CreateWalletTangemWallet(
|
||||||
primaryCard = result.data
|
primaryCard = result.data
|
||||||
when {
|
when {
|
||||||
card.settings.isHDWalletAllowed -> {
|
card.settings.isHDWalletAllowed -> {
|
||||||
deriveKeys(card, createWalletResponse, session, callback)
|
deriveKeys(
|
||||||
|
card = card,
|
||||||
|
createWalletResponses = createWalletResponses,
|
||||||
|
session = session,
|
||||||
|
callback = callback,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
callback(
|
callback(
|
||||||
CompletionResult.Success(
|
CompletionResult.Success(
|
||||||
CreateProductWalletTaskResponse(
|
CreateProductWalletTaskResponse(
|
||||||
card = session.environment.card!!,
|
card = requireNotNull(session.environment.card),
|
||||||
primaryCard = primaryCard,
|
primaryCard = primaryCard,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -282,13 +312,13 @@ private class CreateWalletTangemWallet(
|
||||||
|
|
||||||
private fun deriveKeys(
|
private fun deriveKeys(
|
||||||
card: CardDTO,
|
card: CardDTO,
|
||||||
createWalletResponse: List<CreateWalletResponse>,
|
createWalletResponses: List<CreateWalletResponse>,
|
||||||
session: CardSession,
|
session: CardSession,
|
||||||
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
|
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
|
||||||
) {
|
) {
|
||||||
val map = mutableMapOf<ByteArrayKey, List<DerivationPath>>()
|
val map = mutableMapOf<ByteArrayKey, List<DerivationPath>>()
|
||||||
var isBlockchainsForCurvesExist = false
|
var isBlockchainsForCurvesExist = false
|
||||||
createWalletResponse.forEach { response ->
|
createWalletResponses.forEach { response ->
|
||||||
val blockchainsForCurve = getBlockchains(response.cardId, card).filter {
|
val blockchainsForCurve = getBlockchains(response.cardId, card).filter {
|
||||||
it.getSupportedCurves().contains(response.wallet.curve)
|
it.getSupportedCurves().contains(response.wallet.curve)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class CreateWalletsTask(
|
||||||
callback: (result: CompletionResult<CreateWalletsResponse>) -> Unit,
|
callback: (result: CompletionResult<CreateWalletsResponse>) -> Unit,
|
||||||
) {
|
) {
|
||||||
val extendedPrivateKey = mnemonic?.let {
|
val extendedPrivateKey = mnemonic?.let {
|
||||||
AnyMasterKeyFactory(mnemonic = it, passphrase = passphrase ?: "").makeMasterKey(curve)
|
AnyMasterKeyFactory(mnemonic = it, passphrase = passphrase.orEmpty()).makeMasterKey(curve)
|
||||||
}
|
}
|
||||||
CreateWalletTask(curve, extendedPrivateKey).run(session) { result ->
|
CreateWalletTask(curve, extendedPrivateKey).run(session) { result ->
|
||||||
when (result) {
|
when (result) {
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,10 @@ internal class DerivationsFinder(
|
||||||
val userWalletId = UserWalletIdBuilder.card(card).build() ?: return emptySet()
|
val userWalletId = UserWalletIdBuilder.card(card).build() ?: return emptySet()
|
||||||
val derivationStyle = derivationStyleProvider.getDerivationStyle()
|
val derivationStyle = derivationStyleProvider.getDerivationStyle()
|
||||||
|
|
||||||
var blockchains = withContext(dispatchers.io) {
|
val blockchains = withContext(dispatchers.io) {
|
||||||
getBlockchains(userWalletId)
|
getBlockchains(userWalletId)
|
||||||
}
|
}.ifEmpty {
|
||||||
|
if (DemoHelper.isDemoCardId(card.cardId)) {
|
||||||
if (blockchains.isEmpty()) {
|
|
||||||
blockchains = if (DemoHelper.isDemoCardId(card.cardId)) {
|
|
||||||
getDemoBlockchains(derivationStyle)
|
getDemoBlockchains(derivationStyle)
|
||||||
} else {
|
} else {
|
||||||
getDefaultBlockchains(derivationStyle)
|
getDefaultBlockchains(derivationStyle)
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,15 @@ class ResetToFactorySettingsTask(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deleteWallets(session: CardSession, callback: (result: CompletionResult<Boolean>) -> Unit) {
|
private fun deleteWallets(session: CardSession, callback: (result: CompletionResult<Boolean>) -> Unit) {
|
||||||
val wallet = session.environment.card?.wallets?.lastOrNull().guard {
|
val wallet = session
|
||||||
resetBackup(session, callback)
|
.environment
|
||||||
return
|
.card
|
||||||
}
|
?.wallets
|
||||||
|
?.lastOrNull()
|
||||||
|
.guard {
|
||||||
|
resetBackup(session, callback)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
PurgeWalletCommand(wallet.publicKey).run(session) { result ->
|
PurgeWalletCommand(wallet.publicKey).run(session) { result ->
|
||||||
when (result) {
|
when (result) {
|
||||||
|
|
|
||||||
|
|
@ -111,13 +111,13 @@ internal class ScanProductTask(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getErrorIfExcludedCard(cardDto: CardDTO, card: Card): TangemError? {
|
private fun getErrorIfExcludedCard(cardDto: CardDTO, card: Card): TangemError? {
|
||||||
if (cardDto.isExcluded) return TapSdkError.CardForDifferentApp
|
if (cardDto.isExcluded) return TapSdkError.CardForDifferentApp()
|
||||||
if (cardDto.isNotSupportedInThatRelease) return TapSdkError.CardNotSupportedByRelease
|
if (cardDto.isNotSupportedInThatRelease) return TapSdkError.CardNotSupportedByRelease()
|
||||||
// according ios decline card lower Ed25519Slip0010Available version and contains imported wallets
|
// according ios decline card lower Ed25519Slip0010Available version and contains imported wallets
|
||||||
if (card.firmwareVersion < FirmwareVersion.Ed25519Slip0010Available &&
|
if (card.firmwareVersion < FirmwareVersion.Ed25519Slip0010Available &&
|
||||||
card.wallets.any { it.isImported }
|
card.wallets.any { it.isImported }
|
||||||
) {
|
) {
|
||||||
return TapSdkError.CardNotSupportedByRelease
|
return TapSdkError.CardNotSupportedByRelease()
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
@ -253,12 +253,13 @@ private class ScanWalletProcessor(
|
||||||
callback: (result: CompletionResult<ScanResponse>) -> Unit,
|
callback: (result: CompletionResult<ScanResponse>) -> Unit,
|
||||||
) {
|
) {
|
||||||
mainScope.launch {
|
mainScope.launch {
|
||||||
val activationInProgress = store.inject(DaggerGraphState::cardRepository)
|
val isActivationInProgress = store.inject(DaggerGraphState::cardRepository)
|
||||||
.isActivationInProgress(card.cardId)
|
.isActivationInProgress(card.cardId)
|
||||||
|
|
||||||
@Suppress("ComplexCondition")
|
@Suppress("ComplexCondition")
|
||||||
if (card.backupStatus == CardDTO.BackupStatus.NoBackup && card.wallets.isNotEmpty() &&
|
if (card.backupStatus == CardDTO.BackupStatus.NoBackup &&
|
||||||
activationInProgress
|
card.wallets.isNotEmpty() &&
|
||||||
|
isActivationInProgress
|
||||||
) {
|
) {
|
||||||
StartPrimaryCardLinkingTask().run(session) { linkingResult ->
|
StartPrimaryCardLinkingTask().run(session) { linkingResult ->
|
||||||
when (linkingResult) {
|
when (linkingResult) {
|
||||||
|
|
@ -372,8 +373,8 @@ private class ScanTwinProcessor : ProductCommandProcessor<ScanResponse> {
|
||||||
return@run
|
return@run
|
||||||
}
|
}
|
||||||
|
|
||||||
val verified = TwinsHelper.verifyTwinPublicKey(readDataResult.data.issuerData, publicKey)
|
val isVerified = TwinsHelper.verifyTwinPublicKey(readDataResult.data.issuerData, publicKey)
|
||||||
val response = if (verified) {
|
val response = if (isVerified) {
|
||||||
val twinPublicKey = readDataResult.data.issuerData.sliceArray(0 until 65)
|
val twinPublicKey = readDataResult.data.issuerData.sliceArray(0 until 65)
|
||||||
val walletData = session.environment.walletData
|
val walletData = session.environment.walletData
|
||||||
ScanResponse(
|
ScanResponse(
|
||||||
|
|
|
||||||
|
|
@ -153,9 +153,9 @@ class VisaCardActivationTask @AssistedInject constructor(
|
||||||
val otpTaskDeferred = async { createOTP() }
|
val otpTaskDeferred = async { createOTP() }
|
||||||
|
|
||||||
val dataToSign = dataToSignDeferred.await()
|
val dataToSign = dataToSignDeferred.await()
|
||||||
.getOrElse {
|
.getOrElse { error ->
|
||||||
otpTaskDeferred.cancel()
|
otpTaskDeferred.cancel()
|
||||||
return@coroutineScope CompletionResult.Failure(it)
|
return@coroutineScope CompletionResult.Failure(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
otpTaskDeferred.await()
|
otpTaskDeferred.await()
|
||||||
|
|
|
||||||
|
|
@ -115,8 +115,8 @@ class VisaCustomerWalletApproveTask(
|
||||||
extendedPublicKey = extendedPublicKey,
|
extendedPublicKey = extendedPublicKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
validationResult.onLeft {
|
validationResult.onLeft { error ->
|
||||||
callback(CompletionResult.Failure(it.tangemError))
|
callback(CompletionResult.Failure(error.tangemError))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,8 +137,8 @@ class VisaCustomerWalletApproveTask(
|
||||||
val publicKey = findKeyWithoutDerivation(
|
val publicKey = findKeyWithoutDerivation(
|
||||||
targetAddress = visaDataForApprove.targetAddress,
|
targetAddress = visaDataForApprove.targetAddress,
|
||||||
card = CardDTO(card),
|
card = CardDTO(card),
|
||||||
).getOrElse {
|
).getOrElse { error ->
|
||||||
callback(CompletionResult.Failure(it.tangemError))
|
callback(CompletionResult.Failure(error.tangemError))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ class CreateSecondTwinWalletTask(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TwinsHelper.isTwinsCompatible(firstCardId, card.cardId)) {
|
if (!TwinsHelper.isTwinsCompatible(firstCardId, card.cardId)) {
|
||||||
callback(CompletionResult.Failure(IncompatibleTwinCard))
|
callback(CompletionResult.Failure(IncompatibleTwinCard()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class FinalizeTwinTask(
|
||||||
when (readResult) {
|
when (readResult) {
|
||||||
is CompletionResult.Success ->
|
is CompletionResult.Success ->
|
||||||
ScanProductTask(
|
ScanProductTask(
|
||||||
readResult.data,
|
card = readResult.data,
|
||||||
derivationsFinder = null,
|
derivationsFinder = null,
|
||||||
visaCardScanHandler = null,
|
visaCardScanHandler = null,
|
||||||
visaCoroutineScope = null,
|
visaCoroutineScope = null,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import com.tangem.common.core.TangemError
|
||||||
import com.tangem.tap.tangemSdkManager
|
import com.tangem.tap.tangemSdkManager
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
|
|
||||||
object IncompatibleTwinCard : TangemError(code = 50005) {
|
class IncompatibleTwinCard : TangemError(code = 50005) {
|
||||||
override var customMessage: String = tangemSdkManager.getString(
|
override var customMessage: String = tangemSdkManager.getString(
|
||||||
R.string.twin_error_wrong_twin,
|
R.string.twin_error_wrong_twin,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ class TwinCardsManager(card: CardDTO) {
|
||||||
creatingWalletMessage: Message,
|
creatingWalletMessage: Message,
|
||||||
): CompletionResult<CreateWalletResponse> {
|
): CompletionResult<CreateWalletResponse> {
|
||||||
val response = tangemSdkManager.createSecondTwinWallet(
|
val response = tangemSdkManager.createSecondTwinWallet(
|
||||||
firstPublicKey = currentCardPublicKey!!,
|
firstPublicKey = requireNotNull(currentCardPublicKey),
|
||||||
firstCardId = firstCardId,
|
firstCardId = firstCardId,
|
||||||
issuerKeys = getIssuerKeys(),
|
issuerKeys = getIssuerKeys(),
|
||||||
preparingMessage = preparingMessage,
|
preparingMessage = preparingMessage,
|
||||||
|
|
@ -58,7 +58,7 @@ class TwinCardsManager(card: CardDTO) {
|
||||||
|
|
||||||
suspend fun complete(message: Message): CompletionResult<ScanResponse> {
|
suspend fun complete(message: Message): CompletionResult<ScanResponse> {
|
||||||
val response = tangemSdkManager.finalizeTwin(
|
val response = tangemSdkManager.finalizeTwin(
|
||||||
secondCardPublicKey = secondCardPublicKey!!.hexToBytes(),
|
secondCardPublicKey = requireNotNull(secondCardPublicKey).hexToBytes(),
|
||||||
issuerKeyPair = getIssuerKeys(),
|
issuerKeyPair = getIssuerKeys(),
|
||||||
cardId = firstCardId,
|
cardId = firstCardId,
|
||||||
initialMessage = message,
|
initialMessage = message,
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,9 @@ class WriteProtectedIssuerDataTask(
|
||||||
|
|
||||||
override fun run(session: CardSession, callback: (result: CompletionResult<SuccessResponse>) -> Unit) {
|
override fun run(session: CardSession, callback: (result: CompletionResult<SuccessResponse>) -> Unit) {
|
||||||
SignHashCommand(
|
SignHashCommand(
|
||||||
twinPublicKey.calculateSha256(),
|
hash = twinPublicKey.calculateSha256(),
|
||||||
session.environment.card!!.wallets.first().publicKey,
|
walletPublicKey = requireNotNull(session.environment.card)
|
||||||
|
.wallets.first().publicKey,
|
||||||
)
|
)
|
||||||
.run(session) { signResult ->
|
.run(session) { signResult ->
|
||||||
when (signResult) {
|
when (signResult) {
|
||||||
|
|
@ -31,12 +32,12 @@ class WriteProtectedIssuerDataTask(
|
||||||
when (readResult) {
|
when (readResult) {
|
||||||
is CompletionResult.Success -> {
|
is CompletionResult.Success -> {
|
||||||
writeIssuerData(
|
writeIssuerData(
|
||||||
twinPublicKey,
|
twinPublicKey = twinPublicKey,
|
||||||
issuerKeys,
|
issuerKeys = issuerKeys,
|
||||||
signResult.data.signature,
|
cardSignature = signResult.data.signature,
|
||||||
readResult.data,
|
readResponse = readResult.data,
|
||||||
session,
|
session = session,
|
||||||
callback,
|
callback = callback,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is CompletionResult.Failure -> callback(
|
is CompletionResult.Failure -> callback(
|
||||||
|
|
@ -78,7 +79,7 @@ class WriteProtectedIssuerDataTask(
|
||||||
)
|
)
|
||||||
WriteIssuerDataCommand(
|
WriteIssuerDataCommand(
|
||||||
issuerData = data,
|
issuerData = data,
|
||||||
issuerDataSignature = signedByIssuer.finalizingSignature!!,
|
issuerDataSignature = requireNotNull(signedByIssuer.finalizingSignature),
|
||||||
issuerDataCounter = counter,
|
issuerDataCounter = counter,
|
||||||
issuerPublicKey = issuerKeys.publicKey,
|
issuerPublicKey = issuerKeys.publicKey,
|
||||||
).run(session, callback)
|
).run(session, callback)
|
||||||
|
|
|
||||||
|
|
@ -57,12 +57,12 @@ internal class BiometricUserWalletsListManager(
|
||||||
override val selectedUserWalletSync: UserWallet?
|
override val selectedUserWalletSync: UserWallet?
|
||||||
get() = findSelectedUserWallet()
|
get() = findSelectedUserWallet()
|
||||||
|
|
||||||
override val isLocked: Flow<Boolean>
|
override val lockedState: Flow<Boolean>
|
||||||
get() = state
|
get() = state
|
||||||
.mapLatest { it.isLocked }
|
.mapLatest { it.isLocked }
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
|
|
||||||
override val isLockedSync: Boolean
|
override val isLocked: Boolean
|
||||||
get() = state.value.isLocked
|
get() = state.value.isLocked
|
||||||
|
|
||||||
override val hasUserWallets: Boolean
|
override val hasUserWallets: Boolean
|
||||||
|
|
@ -103,7 +103,9 @@ internal class BiometricUserWalletsListManager(
|
||||||
|
|
||||||
override suspend fun select(userWalletId: UserWalletId): CompletionResult<UserWallet> = catching {
|
override suspend fun select(userWalletId: UserWalletId): CompletionResult<UserWallet> = catching {
|
||||||
if (state.value.selectedUserWalletId == userWalletId) {
|
if (state.value.selectedUserWalletId == userWalletId) {
|
||||||
return@catching findSelectedUserWallet()!!
|
return@catching requireNotNull(findSelectedUserWallet()) {
|
||||||
|
"Wallet is not found"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedUserWalletRepository.set(userWalletId)
|
selectedUserWalletRepository.set(userWalletId)
|
||||||
|
|
|
||||||
|
|
@ -93,23 +93,23 @@ internal class GeneralUserWalletsListManager(
|
||||||
override val walletsCount: Int
|
override val walletsCount: Int
|
||||||
get() = requireImplementation.walletsCount
|
get() = requireImplementation.walletsCount
|
||||||
|
|
||||||
override val isLocked: Flow<Boolean>
|
override val lockedState: Flow<Boolean>
|
||||||
get() = implementation.transformLatest { impl ->
|
get() = implementation.transformLatest { impl ->
|
||||||
if (impl == null) return@transformLatest
|
if (impl == null) return@transformLatest
|
||||||
|
|
||||||
if (impl is UserWalletsListManager.Lockable) {
|
if (impl is UserWalletsListManager.Lockable) {
|
||||||
emitAll(impl.isLocked)
|
emitAll(impl.lockedState)
|
||||||
} else {
|
} else {
|
||||||
error("RuntimeUserWalletsListManager is not lockable")
|
error("RuntimeUserWalletsListManager is not lockable")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isLockedSync: Boolean
|
override val isLocked: Boolean
|
||||||
get() {
|
get() {
|
||||||
val impl = requireImplementation
|
val impl = requireImplementation
|
||||||
|
|
||||||
return if (impl is UserWalletsListManager.Lockable) {
|
return if (impl is UserWalletsListManager.Lockable) {
|
||||||
impl.isLockedSync
|
impl.isLocked
|
||||||
} else {
|
} else {
|
||||||
error("RuntimeUserWalletsListManager is not lockable")
|
error("RuntimeUserWalletsListManager is not lockable")
|
||||||
}
|
}
|
||||||
|
|
@ -173,10 +173,10 @@ internal class GeneralUserWalletsListManager(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (possibleManager == implementation.value) {
|
if (possibleManager == implementation.value) {
|
||||||
Timber.e("Switch to the same manager ${possibleManager::class.simpleName}")
|
Timber.e("Switch to the same manager ${possibleManager::class.simpleName.orEmpty()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
Timber.i("Switch to ${possibleManager::class.simpleName}")
|
Timber.i("Switch to ${possibleManager::class.simpleName.orEmpty()}")
|
||||||
|
|
||||||
val previousManager = implementation.value
|
val previousManager = implementation.value
|
||||||
implementation.value = copySelectedUserWallet(
|
implementation.value = copySelectedUserWallet(
|
||||||
|
|
|
||||||
|
|
@ -74,11 +74,13 @@ internal class RuntimeUserWalletsListManager : UserWalletsListManager {
|
||||||
?.takeIf { it.walletId == userWalletId }
|
?.takeIf { it.walletId == userWalletId }
|
||||||
?: walletNotFound()
|
?: walletNotFound()
|
||||||
|
|
||||||
state.updateAndGet { prevState ->
|
requireNotNull(
|
||||||
prevState.copy(
|
state.updateAndGet { prevState ->
|
||||||
userWallet = update(wallet),
|
prevState.copy(
|
||||||
)
|
userWallet = update(wallet),
|
||||||
}.userWallet!!
|
)
|
||||||
|
}.userWallet,
|
||||||
|
) { "User wallet is null after update" }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(userWalletIds: List<UserWalletId>): CompletionResult<Unit> = clear()
|
override suspend fun delete(userWalletIds: List<UserWalletId>): CompletionResult<Unit> = clear()
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ internal data class UserWalletSensitiveInformation(
|
||||||
val mobileWallets: List<MobileWallet>? = null,
|
val mobileWallets: List<MobileWallet>? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Suppress("BooleanPropertyNaming")
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class UserWalletPublicInformation(
|
internal data class UserWalletPublicInformation(
|
||||||
// Common
|
// Common
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ internal class DefaultUserWalletsListRepository(
|
||||||
|
|
||||||
// update the userWallets state and add if it doesn't exist
|
// update the userWallets state and add if it doesn't exist
|
||||||
updateWallets { currentWallets ->
|
updateWallets { currentWallets ->
|
||||||
val wallets = currentWallets ?: emptyList()
|
val wallets = currentWallets.orEmpty()
|
||||||
if (wallets.any { it.walletId == userWallet.walletId }) {
|
if (wallets.any { it.walletId == userWallet.walletId }) {
|
||||||
wallets.map { if (it.walletId == userWallet.walletId) userWallet else it }
|
wallets.map { if (it.walletId == userWallet.walletId) userWallet else it }
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -332,12 +332,12 @@ internal class DefaultUserWalletsListRepository(
|
||||||
raise(LockWalletsError.NothingToLock)
|
raise(LockWalletsError.NothingToLock)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateWallets {
|
updateWallets { wallets ->
|
||||||
it?.map {
|
wallets?.map { wallet ->
|
||||||
if (it.walletId !in unsecuredWalletIds) {
|
if (wallet.walletId !in unsecuredWalletIds) {
|
||||||
it.lock()
|
wallet.lock()
|
||||||
} else {
|
} else {
|
||||||
it
|
wallet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -395,17 +395,17 @@ internal class DefaultUserWalletsListRepository(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun hasBiometry(): Boolean {
|
private suspend fun hasBiometry(): Boolean {
|
||||||
val useBiometricAuthentication = appPreferencesStore.getSyncOrDefault(
|
val isBiometricAuthenticationUsed = appPreferencesStore.getSyncOrDefault(
|
||||||
key = PreferencesKeys.USE_BIOMETRIC_AUTHENTICATION_KEY,
|
key = PreferencesKeys.USE_BIOMETRIC_AUTHENTICATION_KEY,
|
||||||
default = false,
|
default = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
return tangemSdkManagerProvider.invoke().canUseBiometry && useBiometricAuthentication
|
return tangemSdkManagerProvider.invoke().canUseBiometry && isBiometricAuthenticationUsed
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateWallets(block: (List<UserWallet>?) -> List<UserWallet>?) {
|
private fun updateWallets(block: (List<UserWallet>?) -> List<UserWallet>?) {
|
||||||
userWallets.update {
|
userWallets.update { wallets ->
|
||||||
val updated = block(it)
|
val updated = block(wallets)
|
||||||
selectedUserWallet.update { currentSelected ->
|
selectedUserWallet.update { currentSelected ->
|
||||||
if (currentSelected == null) return@update null
|
if (currentSelected == null) return@update null
|
||||||
updated?.find { it.walletId == currentSelected.walletId }
|
updated?.find { it.walletId == currentSelected.walletId }
|
||||||
|
|
|
||||||
|
|
@ -137,8 +137,7 @@ internal class UserWalletEncryptionKeysRepository(
|
||||||
|
|
||||||
private suspend fun UserWalletEncryptionKey.encode(): ByteArray {
|
private suspend fun UserWalletEncryptionKey.encode(): ByteArray {
|
||||||
return withContext(dispatchers.default) {
|
return withContext(dispatchers.default) {
|
||||||
this@encode
|
encryptionKeyAdapter.toJson(this@encode)
|
||||||
.let(encryptionKeyAdapter::toJson)
|
|
||||||
.encodeToByteArray(throwOnInvalidSequence = true)
|
.encodeToByteArray(throwOnInvalidSequence = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -153,8 +152,7 @@ internal class UserWalletEncryptionKeysRepository(
|
||||||
|
|
||||||
private suspend fun List<UserWalletId>.encode(): ByteArray {
|
private suspend fun List<UserWalletId>.encode(): ByteArray {
|
||||||
return withContext(dispatchers.default) {
|
return withContext(dispatchers.default) {
|
||||||
this@encode
|
userWalletsIdsListAdapter.toJson(this@encode)
|
||||||
.let(userWalletsIdsListAdapter::toJson)
|
|
||||||
.encodeToByteArray(throwOnInvalidSequence = true)
|
.encodeToByteArray(throwOnInvalidSequence = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -164,8 +164,7 @@ internal class BiometricUserWalletsKeysRepository(
|
||||||
|
|
||||||
private suspend fun UserWalletEncryptionKey.encode(): ByteArray {
|
private suspend fun UserWalletEncryptionKey.encode(): ByteArray {
|
||||||
return withContext(Dispatchers.Default) {
|
return withContext(Dispatchers.Default) {
|
||||||
this@encode
|
encryptionKeyAdapter.toJson(this@encode)
|
||||||
.let(encryptionKeyAdapter::toJson)
|
|
||||||
.encodeToByteArray(throwOnInvalidSequence = true)
|
.encodeToByteArray(throwOnInvalidSequence = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -180,8 +179,7 @@ internal class BiometricUserWalletsKeysRepository(
|
||||||
|
|
||||||
private suspend fun List<UserWalletId>.encode(): ByteArray {
|
private suspend fun List<UserWalletId>.encode(): ByteArray {
|
||||||
return withContext(Dispatchers.Default) {
|
return withContext(Dispatchers.Default) {
|
||||||
this@encode
|
userWalletsIdsListAdapter.toJson(this@encode)
|
||||||
.let(userWalletsIdsListAdapter::toJson)
|
|
||||||
.encodeToByteArray(throwOnInvalidSequence = true)
|
.encodeToByteArray(throwOnInvalidSequence = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,7 @@ internal class DefaultUserWalletsPublicInformationRepository(
|
||||||
@JvmName("saveWithPublicInformation")
|
@JvmName("saveWithPublicInformation")
|
||||||
private suspend fun save(publicInformation: List<UserWalletPublicInformation>): CompletionResult<Unit> = catching {
|
private suspend fun save(publicInformation: List<UserWalletPublicInformation>): CompletionResult<Unit> = catching {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
publicInformation
|
publicInformationAdapter.toJson(publicInformation)
|
||||||
.let(publicInformationAdapter::toJson)
|
|
||||||
.encodeToByteArray(throwOnInvalidSequence = true)
|
.encodeToByteArray(throwOnInvalidSequence = true)
|
||||||
.also { secureStorage.store(it, StorageKey.UserWalletPublicInformation.name) }
|
.also { secureStorage.store(it, StorageKey.UserWalletPublicInformation.name) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,18 +110,18 @@ internal class DefaultUserWalletsSensitiveInformationRepository(
|
||||||
|
|
||||||
private suspend fun ByteArray.decodeToEncryptedSensitiveInformation(): Map<String, ByteArray>? {
|
private suspend fun ByteArray.decodeToEncryptedSensitiveInformation(): Map<String, ByteArray>? {
|
||||||
return withContext(Dispatchers.Default) {
|
return withContext(Dispatchers.Default) {
|
||||||
this@decodeToEncryptedSensitiveInformation
|
encryptedSensitiveInformationMapAdapter.fromJson(
|
||||||
.decodeToString(throwOnInvalidSequence = true)
|
this@decodeToEncryptedSensitiveInformation.decodeToString(throwOnInvalidSequence = true),
|
||||||
.let(encryptedSensitiveInformationMapAdapter::fromJson)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun ByteArray.decodeToSensitiveInformation(): UserWalletSensitiveInformation? {
|
private suspend fun ByteArray.decodeToSensitiveInformation(): UserWalletSensitiveInformation? {
|
||||||
return withContext(Dispatchers.Default) {
|
return withContext(Dispatchers.Default) {
|
||||||
try {
|
try {
|
||||||
this@decodeToSensitiveInformation
|
sensitiveInformationAdapter.fromJson(
|
||||||
.decodeToString(throwOnInvalidSequence = true)
|
this@decodeToSensitiveInformation.decodeToString(throwOnInvalidSequence = true),
|
||||||
.let(sensitiveInformationAdapter::fromJson)
|
)
|
||||||
} catch (e: CharacterCodingException) {
|
} catch (e: CharacterCodingException) {
|
||||||
Timber.e(e, "Unable to decode sensitive information")
|
Timber.e(e, "Unable to decode sensitive information")
|
||||||
|
|
||||||
|
|
@ -132,16 +132,14 @@ internal class DefaultUserWalletsSensitiveInformationRepository(
|
||||||
|
|
||||||
private suspend fun UserWalletSensitiveInformation.encode(): ByteArray {
|
private suspend fun UserWalletSensitiveInformation.encode(): ByteArray {
|
||||||
return withContext(Dispatchers.Default) {
|
return withContext(Dispatchers.Default) {
|
||||||
this@encode
|
sensitiveInformationAdapter.toJson(this@encode)
|
||||||
.let(sensitiveInformationAdapter::toJson)
|
|
||||||
.encodeToByteArray(throwOnInvalidSequence = true)
|
.encodeToByteArray(throwOnInvalidSequence = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun Map<String, ByteArray>.encode(): ByteArray {
|
private suspend fun Map<String, ByteArray>.encode(): ByteArray {
|
||||||
return withContext(Dispatchers.Default) {
|
return withContext(Dispatchers.Default) {
|
||||||
this@encode
|
encryptedSensitiveInformationMapAdapter.toJson(this@encode)
|
||||||
.let(encryptedSensitiveInformationMapAdapter::toJson)
|
|
||||||
.encodeToByteArray(throwOnInvalidSequence = true)
|
.encodeToByteArray(throwOnInvalidSequence = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,14 +54,14 @@ internal fun UserWalletPublicInformation.toUserWallet(): UserWallet {
|
||||||
walletId = walletId,
|
walletId = walletId,
|
||||||
hotWalletId = hotWalletId,
|
hotWalletId = hotWalletId,
|
||||||
wallets = null,
|
wallets = null,
|
||||||
backedUp = backedUp!!,
|
backedUp = requireNotNull(backedUp),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
UserWallet.Cold(
|
UserWallet.Cold(
|
||||||
name = name,
|
name = name,
|
||||||
walletId = walletId,
|
walletId = walletId,
|
||||||
cardsInWallet = cardsInWallet,
|
cardsInWallet = cardsInWallet,
|
||||||
scanResponse = scanResponse!!,
|
scanResponse = requireNotNull(scanResponse),
|
||||||
isMultiCurrency = isMultiCurrency,
|
isMultiCurrency = isMultiCurrency,
|
||||||
hasBackupError = hasBackupError,
|
hasBackupError = hasBackupError,
|
||||||
)
|
)
|
||||||
|
|
@ -78,7 +78,7 @@ internal fun UserWallet.updateWith(sensitiveInformation: UserWalletSensitiveInfo
|
||||||
copy(
|
copy(
|
||||||
scanResponse = scanResponse.copy(
|
scanResponse = scanResponse.copy(
|
||||||
card = scanResponse.card.copy(
|
card = scanResponse.card.copy(
|
||||||
wallets = sensitiveInformation.wallets!!,
|
wallets = requireNotNull(sensitiveInformation.wallets),
|
||||||
),
|
),
|
||||||
visaCardActivationStatus = sensitiveInformation.visaCardActivationStatus,
|
visaCardActivationStatus = sensitiveInformation.visaCardActivationStatus,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,9 @@ internal class VisaCardScanHandler @Inject constructor(
|
||||||
cardId = card.cardId,
|
cardId = card.cardId,
|
||||||
// This is the wallet public key, not the address and it's alright, as the API expects it in this format
|
// This is the wallet public key, not the address and it's alright, as the API expects it in this format
|
||||||
cardWalletAddress = wallet.publicKey.toHexString(),
|
cardWalletAddress = wallet.publicKey.toHexString(),
|
||||||
).getOrElse {
|
).getOrElse { error ->
|
||||||
Timber.i("Failed to get Access token for Wallet public key authorization")
|
Timber.i("Failed to get Access token for Wallet public key authorization")
|
||||||
return CompletionResult.Failure(it.tangemError)
|
return CompletionResult.Failure(error.tangemError)
|
||||||
}
|
}
|
||||||
|
|
||||||
val signChallengeResult = signChallengeWithWallet(
|
val signChallengeResult = signChallengeWithWallet(
|
||||||
|
|
@ -123,16 +123,16 @@ internal class VisaCardScanHandler @Inject constructor(
|
||||||
signedChallenge: VisaAuthSignedChallenge,
|
signedChallenge: VisaAuthSignedChallenge,
|
||||||
): CompletionResult<VisaCardActivationStatus> {
|
): CompletionResult<VisaCardActivationStatus> {
|
||||||
val authorizationTokensResponse = visaAuthRemoteDataSource.getAccessTokens(signedChallenge = signedChallenge)
|
val authorizationTokensResponse = visaAuthRemoteDataSource.getAccessTokens(signedChallenge = signedChallenge)
|
||||||
.getOrElse {
|
.getOrElse { error ->
|
||||||
Timber.i("Failed to get Access token for Wallet public key authorization.")
|
Timber.i("Failed to get Access token for Wallet public key authorization.")
|
||||||
return if (
|
return if (
|
||||||
it is VisaApiError.ProductInstanceIsNotActivated ||
|
error is VisaApiError.ProductInstanceIsNotActivated ||
|
||||||
it is VisaApiError.ProductInstanceNotFoundActivationRequired
|
error is VisaApiError.ProductInstanceNotFoundActivationRequired
|
||||||
) {
|
) {
|
||||||
Timber.i("Proceeding with card authorization.")
|
Timber.i("Proceeding with card authorization.")
|
||||||
handleCardAuthorization(cardWalletAddress = cardWalletAddress)
|
handleCardAuthorization(cardWalletAddress = cardWalletAddress)
|
||||||
} else {
|
} else {
|
||||||
CompletionResult.Failure(it.tangemError)
|
CompletionResult.Failure(error.tangemError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,9 +152,9 @@ internal class VisaCardScanHandler @Inject constructor(
|
||||||
val challengeResponse = visaAuthRemoteDataSource.getCardAuthChallenge(
|
val challengeResponse = visaAuthRemoteDataSource.getCardAuthChallenge(
|
||||||
cardId = card.cardId,
|
cardId = card.cardId,
|
||||||
cardPublicKey = card.cardPublicKey.toHexString(),
|
cardPublicKey = card.cardPublicKey.toHexString(),
|
||||||
).getOrElse {
|
).getOrElse { error ->
|
||||||
Timber.e("Failed to get challenge for Card authorization. Plain error: ${it.errorCode}")
|
Timber.e("Failed to get challenge for Card authorization. Plain error: ${error.errorCode}")
|
||||||
return CompletionResult.Failure(it.tangemError)
|
return CompletionResult.Failure(error.tangemError)
|
||||||
}
|
}
|
||||||
|
|
||||||
Timber.i("Received challenge to sign: ${challengeResponse.challenge}")
|
Timber.i("Received challenge to sign: ${challengeResponse.challenge}")
|
||||||
|
|
@ -179,9 +179,9 @@ internal class VisaCardScanHandler @Inject constructor(
|
||||||
signedChallenge = attestCardKeyResponse.cardSignature.toHexString(),
|
signedChallenge = attestCardKeyResponse.cardSignature.toHexString(),
|
||||||
salt = attestCardKeyResponse.salt.toHexString(),
|
salt = attestCardKeyResponse.salt.toHexString(),
|
||||||
),
|
),
|
||||||
).getOrElse {
|
).getOrElse { error ->
|
||||||
Timber.e("Failed to sign challenge with Card public key. Plain error: ${it.errorCode}")
|
Timber.e("Failed to sign challenge with Card public key. Plain error: ${error.errorCode}")
|
||||||
return CompletionResult.Failure(it.tangemError)
|
return CompletionResult.Failure(error.tangemError)
|
||||||
}
|
}
|
||||||
|
|
||||||
visaAuthTokenStorage.store(
|
visaAuthTokenStorage.store(
|
||||||
|
|
@ -189,9 +189,9 @@ internal class VisaCardScanHandler @Inject constructor(
|
||||||
tokens = authorizationTokensResponse,
|
tokens = authorizationTokensResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
val activationRemoteState = visaActivationRepository.getActivationRemoteState().getOrElse {
|
val activationRemoteState = visaActivationRepository.getActivationRemoteState().getOrElse { error ->
|
||||||
Timber.e("Failed to sign challenge with Card public key. Plain error: ${it.errorCode}")
|
Timber.e("Failed to sign challenge with Card public key. Plain error: ${error.errorCode}")
|
||||||
return CompletionResult.Failure(it.tangemError)
|
return CompletionResult.Failure(error.tangemError)
|
||||||
}
|
}
|
||||||
|
|
||||||
val error = when (activationRemoteState) {
|
val error = when (activationRemoteState) {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.models.scan.ScanResponse
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import org.rekotlin.Action
|
import org.rekotlin.Action
|
||||||
|
|
||||||
|
@Suppress("BooleanPropertyNaming")
|
||||||
sealed class DetailsAction : Action {
|
sealed class DetailsAction : Action {
|
||||||
|
|
||||||
data class PrepareScreen(
|
data class PrepareScreen(
|
||||||
|
|
@ -32,7 +33,7 @@ sealed class DetailsAction : Action {
|
||||||
|
|
||||||
data object EnrollBiometrics : AppSettings()
|
data object EnrollBiometrics : AppSettings()
|
||||||
data class BiometricsStatusChanged(
|
data class BiometricsStatusChanged(
|
||||||
val needEnrollBiometrics: Boolean,
|
val isEnrollBiometricsNeeded: Boolean,
|
||||||
) : AppSettings()
|
) : AppSettings()
|
||||||
|
|
||||||
data class ChangeAppThemeMode(
|
data class ChangeAppThemeMode(
|
||||||
|
|
@ -40,7 +41,7 @@ sealed class DetailsAction : Action {
|
||||||
) : AppSettings()
|
) : AppSettings()
|
||||||
|
|
||||||
data class ChangeBalanceHiding(
|
data class ChangeBalanceHiding(
|
||||||
val hideBalance: Boolean,
|
val shouldHideBalance: Boolean,
|
||||||
) : AppSettings()
|
) : AppSettings()
|
||||||
|
|
||||||
data class ChangeAppCurrency(
|
data class ChangeAppCurrency(
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ class DetailsMiddleware {
|
||||||
changeAppThemeMode(action.appThemeMode)
|
changeAppThemeMode(action.appThemeMode)
|
||||||
}
|
}
|
||||||
is DetailsAction.AppSettings.ChangeBalanceHiding -> {
|
is DetailsAction.AppSettings.ChangeBalanceHiding -> {
|
||||||
changeBalanceHiding(action.hideBalance)
|
changeBalanceHiding(action.shouldHideBalance)
|
||||||
}
|
}
|
||||||
is DetailsAction.AppSettings.ChangeAppCurrency -> {
|
is DetailsAction.AppSettings.ChangeAppCurrency -> {
|
||||||
store.dispatch(GlobalAction.ChangeAppCurrency(action.currency))
|
store.dispatch(GlobalAction.ChangeAppCurrency(action.currency))
|
||||||
|
|
@ -153,9 +153,9 @@ class DetailsMiddleware {
|
||||||
private suspend fun setBiometricLockForAllWallets() {
|
private suspend fun setBiometricLockForAllWallets() {
|
||||||
val userWalletsListRepository = store.inject(DaggerGraphState::userWalletsListRepository)
|
val userWalletsListRepository = store.inject(DaggerGraphState::userWalletsListRepository)
|
||||||
val userWallets = userWalletsListRepository.userWalletsSync()
|
val userWallets = userWalletsListRepository.userWalletsSync()
|
||||||
userWallets.forEach {
|
userWallets.forEach { wallet ->
|
||||||
userWalletsListRepository.setLock(
|
userWalletsListRepository.setLock(
|
||||||
userWalletId = it.walletId,
|
userWalletId = wallet.walletId,
|
||||||
lockMethod = LockMethod.Biometric,
|
lockMethod = LockMethod.Biometric,
|
||||||
changeUnsecured = false,
|
changeUnsecured = false,
|
||||||
)
|
)
|
||||||
|
|
@ -174,11 +174,11 @@ class DetailsMiddleware {
|
||||||
deleteSavedAccessCodes()
|
deleteSavedAccessCodes()
|
||||||
val userWalletsListRepository = store.inject(DaggerGraphState::userWalletsListRepository)
|
val userWalletsListRepository = store.inject(DaggerGraphState::userWalletsListRepository)
|
||||||
val tangemHotSdk = store.inject(DaggerGraphState::tangemHotSdk)
|
val tangemHotSdk = store.inject(DaggerGraphState::tangemHotSdk)
|
||||||
userWalletsListRepository.userWalletsSync().forEach {
|
userWalletsListRepository.userWalletsSync().forEach { wallet ->
|
||||||
if (it is UserWallet.Hot) {
|
if (wallet is UserWallet.Hot) {
|
||||||
userWalletsListRepository.saveWithoutLock(
|
userWalletsListRepository.saveWithoutLock(
|
||||||
userWallet = it.copy(
|
userWallet = wallet.copy(
|
||||||
hotWalletId = tangemHotSdk.removeBiometryAuthIfPresented(it.hotWalletId),
|
hotWalletId = tangemHotSdk.removeBiometryAuthIfPresented(wallet.hotWalletId),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -188,10 +188,10 @@ class DetailsMiddleware {
|
||||||
private fun observeBiometricsStatusChanges(scope: CoroutineScope) {
|
private fun observeBiometricsStatusChanges(scope: CoroutineScope) {
|
||||||
val needEnrollBiometricsFlow = flow {
|
val needEnrollBiometricsFlow = flow {
|
||||||
do {
|
do {
|
||||||
val needEnrollBiometrics = runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull()
|
val isEnrollBiometricsNeeded = runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull()
|
||||||
|
|
||||||
if (needEnrollBiometrics != null) {
|
if (isEnrollBiometricsNeeded != null) {
|
||||||
emit(needEnrollBiometrics)
|
emit(isEnrollBiometricsNeeded)
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(timeMillis = 200)
|
delay(timeMillis = 200)
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ private fun handlePrivacyAction(action: DetailsAction.AppSettings, state: Detail
|
||||||
)
|
)
|
||||||
is DetailsAction.AppSettings.BiometricsStatusChanged -> state.copy(
|
is DetailsAction.AppSettings.BiometricsStatusChanged -> state.copy(
|
||||||
appSettingsState = state.appSettingsState.copy(
|
appSettingsState = state.appSettingsState.copy(
|
||||||
needEnrollBiometrics = action.needEnrollBiometrics,
|
needEnrollBiometrics = action.isEnrollBiometricsNeeded,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
is DetailsAction.AppSettings.ChangeAppThemeMode -> state.copy(
|
is DetailsAction.AppSettings.ChangeAppThemeMode -> state.copy(
|
||||||
|
|
@ -99,7 +99,7 @@ private fun handlePrivacyAction(action: DetailsAction.AppSettings, state: Detail
|
||||||
)
|
)
|
||||||
is DetailsAction.AppSettings.ChangeBalanceHiding -> state.copy(
|
is DetailsAction.AppSettings.ChangeBalanceHiding -> state.copy(
|
||||||
appSettingsState = state.appSettingsState.copy(
|
appSettingsState = state.appSettingsState.copy(
|
||||||
isHidingEnabled = action.hideBalance,
|
isHidingEnabled = action.shouldHideBalance,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
// state should be copied to avoid concurrent modifications from different sources
|
// state should be copied to avoid concurrent modifications from different sources
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ data class DetailsState(
|
||||||
val appSettingsState: AppSettingsState = AppSettingsState(),
|
val appSettingsState: AppSettingsState = AppSettingsState(),
|
||||||
) : StateType
|
) : StateType
|
||||||
|
|
||||||
|
@Suppress("BooleanPropertyNaming")
|
||||||
data class AppSettingsState(
|
data class AppSettingsState(
|
||||||
@Deprecated("Delete after hot wallet release")
|
@Deprecated("Delete after hot wallet release")
|
||||||
val saveWallets: Boolean = false,
|
val saveWallets: Boolean = false,
|
||||||
|
|
|
||||||
|
|
@ -341,16 +341,16 @@ private class AppCurrencySelectorStateProvider : CollectionPreviewParameterProvi
|
||||||
.mapIndexed { index, s -> Currency(index.toString(), s) }
|
.mapIndexed { index, s -> Currency(index.toString(), s) }
|
||||||
.toPersistentList()
|
.toPersistentList()
|
||||||
|
|
||||||
AppCurrencySelectorState.Loading(onBackClick = {}).let(::add)
|
add(AppCurrencySelectorState.Loading(onBackClick = {}))
|
||||||
AppCurrencySelectorState.Default(
|
add(AppCurrencySelectorState.Default(
|
||||||
selectedId = "0",
|
selectedId = "0",
|
||||||
items = items,
|
items = items,
|
||||||
scrollToSelected = consumedEvent(),
|
scrollToSelected = consumedEvent(),
|
||||||
onCurrencyClick = {},
|
onCurrencyClick = {},
|
||||||
onBackClick = {},
|
onBackClick = {},
|
||||||
onTopBarActionClick = {},
|
onTopBarActionClick = {},
|
||||||
).let(::add)
|
))
|
||||||
AppCurrencySelectorState.Search(
|
add(AppCurrencySelectorState.Search(
|
||||||
selectedId = "0",
|
selectedId = "0",
|
||||||
items = items,
|
items = items,
|
||||||
scrollToSelected = consumedEvent(),
|
scrollToSelected = consumedEvent(),
|
||||||
|
|
@ -358,7 +358,7 @@ private class AppCurrencySelectorStateProvider : CollectionPreviewParameterProvi
|
||||||
onBackClick = {},
|
onBackClick = {},
|
||||||
onSearchInputChange = {},
|
onSearchInputChange = {},
|
||||||
onTopBarActionClick = {},
|
onTopBarActionClick = {},
|
||||||
).let(::add)
|
))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
// endregion Preview
|
// endregion Preview
|
||||||
|
|
@ -27,16 +27,16 @@ import kotlinx.collections.immutable.persistentListOf
|
||||||
@Composable
|
@Composable
|
||||||
internal fun AppSettingsScreen(state: AppSettingsScreenState, onBackClick: () -> Unit, modifier: Modifier = Modifier) {
|
internal fun AppSettingsScreen(state: AppSettingsScreenState, onBackClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||||
SettingsScreensScaffold(
|
SettingsScreensScaffold(
|
||||||
|
onBackClick = onBackClick,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
titleRes = R.string.app_settings_title,
|
||||||
|
addBottomInsets = false,
|
||||||
content = {
|
content = {
|
||||||
when (state) {
|
when (state) {
|
||||||
is AppSettingsScreenState.Content -> AppSettings(state = state)
|
is AppSettingsScreenState.Content -> AppSettings(state = state)
|
||||||
is AppSettingsScreenState.Loading -> Unit
|
is AppSettingsScreenState.Loading -> Unit
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
titleRes = R.string.app_settings_title,
|
|
||||||
onBackClick = onBackClick,
|
|
||||||
addBottomInsets = false,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,10 +103,10 @@ private class AppSettingsScreenStateProvider : CollectionPreviewParameterProvide
|
||||||
itemsFactory.createSelectThemeModeButton(AppThemeMode.DEFAULT, {}),
|
itemsFactory.createSelectThemeModeButton(AppThemeMode.DEFAULT, {}),
|
||||||
)
|
)
|
||||||
|
|
||||||
AppSettingsScreenState.Content(
|
add(AppSettingsScreenState.Content(
|
||||||
items = items,
|
items = items,
|
||||||
dialog = null,
|
dialog = null,
|
||||||
).let(::add)
|
))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
// endregion Preview
|
// endregion Preview
|
||||||
|
|
@ -47,8 +47,8 @@ private class AlertDialogProvider : CollectionPreviewParameterProvider<Dialog.Al
|
||||||
collection = buildList {
|
collection = buildList {
|
||||||
val dialogsFactory = AppSettingsDialogsFactory()
|
val dialogsFactory = AppSettingsDialogsFactory()
|
||||||
|
|
||||||
dialogsFactory.createDeleteSavedAccessCodesAlert({}, {}).let(::add)
|
add(dialogsFactory.createDeleteSavedAccessCodesAlert({}, {}))
|
||||||
dialogsFactory.createDeleteSavedWalletsAlert({}, {}).let(::add)
|
add(dialogsFactory.createDeleteSavedWalletsAlert({}, {}))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
// endregion Preview
|
// endregion Preview
|
||||||
|
|
@ -64,10 +64,10 @@ private class ButtonItemProvider : CollectionPreviewParameterProvider<Item.Butto
|
||||||
collection = buildList {
|
collection = buildList {
|
||||||
val itemsFactory = AppSettingsItemsFactory()
|
val itemsFactory = AppSettingsItemsFactory()
|
||||||
|
|
||||||
itemsFactory.createSelectAppCurrencyButton(
|
add(itemsFactory.createSelectAppCurrencyButton(
|
||||||
currentAppCurrencyName = "US Dollar",
|
currentAppCurrencyName = "US Dollar",
|
||||||
onClick = { /* no-op */ },
|
onClick = { /* no-op */ },
|
||||||
).let(::add)
|
))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
// endregion Preview
|
// endregion Preview
|
||||||
|
|
@ -71,9 +71,9 @@ private class CardItemProvider : CollectionPreviewParameterProvider<Item.Card>(
|
||||||
collection = buildList {
|
collection = buildList {
|
||||||
val itemsFactory = AppSettingsItemsFactory()
|
val itemsFactory = AppSettingsItemsFactory()
|
||||||
|
|
||||||
itemsFactory.createEnrollBiometricsCard(
|
add(itemsFactory.createEnrollBiometricsCard(
|
||||||
onClick = { /* no-op */ },
|
onClick = { /* no-op */ },
|
||||||
).let(::add)
|
))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
// endregion Preview
|
// endregion Preview
|
||||||
|
|
@ -85,26 +85,26 @@ private class SwitchItemProvider : CollectionPreviewParameterProvider<Item.Switc
|
||||||
collection = buildList {
|
collection = buildList {
|
||||||
val itemsFactory = AppSettingsItemsFactory()
|
val itemsFactory = AppSettingsItemsFactory()
|
||||||
|
|
||||||
itemsFactory.createSaveAccessCodeSwitch(
|
add(itemsFactory.createSaveAccessCodeSwitch(
|
||||||
isChecked = true,
|
isChecked = true,
|
||||||
isEnabled = true,
|
isEnabled = true,
|
||||||
onCheckedChange = { /* no-op */ },
|
onCheckedChange = { /* no-op */ },
|
||||||
).let(::add)
|
))
|
||||||
itemsFactory.createSaveAccessCodeSwitch(
|
add(itemsFactory.createSaveAccessCodeSwitch(
|
||||||
isChecked = false,
|
isChecked = false,
|
||||||
isEnabled = true,
|
isEnabled = true,
|
||||||
onCheckedChange = { /* no-op */ },
|
onCheckedChange = { /* no-op */ },
|
||||||
).let(::add)
|
))
|
||||||
itemsFactory.createSaveAccessCodeSwitch(
|
add(itemsFactory.createSaveAccessCodeSwitch(
|
||||||
isChecked = true,
|
isChecked = true,
|
||||||
isEnabled = false,
|
isEnabled = false,
|
||||||
onCheckedChange = { /* no-op */ },
|
onCheckedChange = { /* no-op */ },
|
||||||
).let(::add)
|
))
|
||||||
itemsFactory.createSaveAccessCodeSwitch(
|
add(itemsFactory.createSaveAccessCodeSwitch(
|
||||||
isChecked = false,
|
isChecked = false,
|
||||||
isEnabled = false,
|
isEnabled = false,
|
||||||
onCheckedChange = { /* no-op */ },
|
onCheckedChange = { /* no-op */ },
|
||||||
).let(::add)
|
))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
// endregion Preview
|
// endregion Preview
|
||||||
|
|
@ -99,60 +99,76 @@ internal class AppSettingsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildItems(state: AppSettingsState): ImmutableList<AppSettingsScreenState.Item> {
|
private fun buildItems(state: AppSettingsState): ImmutableList<AppSettingsScreenState.Item> {
|
||||||
val items = buildList {
|
val items = buildList<AppSettingsScreenState.Item> {
|
||||||
if (state.needEnrollBiometrics) {
|
if (state.needEnrollBiometrics) {
|
||||||
itemsFactory.createEnrollBiometricsCard(
|
add(
|
||||||
onClick = ::enrollBiometrics,
|
itemsFactory.createEnrollBiometricsCard(
|
||||||
).let(::add)
|
onClick = ::enrollBiometrics,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
itemsFactory.createSelectAppCurrencyButton(
|
add(
|
||||||
currentAppCurrencyName = state.selectedAppCurrency.name,
|
itemsFactory.createSelectAppCurrencyButton(
|
||||||
onClick = ::showAppCurrencySelector,
|
currentAppCurrencyName = state.selectedAppCurrency.name,
|
||||||
).let(::add)
|
onClick = ::showAppCurrencySelector,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
if (hotWalletFeatureToggles.isHotWalletEnabled) {
|
if (hotWalletFeatureToggles.isHotWalletEnabled) {
|
||||||
val canUseBiometrics = !state.needEnrollBiometrics && !state.isInProgress
|
val canUseBiometrics = !state.needEnrollBiometrics && !state.isInProgress
|
||||||
|
|
||||||
itemsFactory.createUseBiometricsSwitch(
|
add(
|
||||||
isChecked = state.useBiometricAuthentication,
|
itemsFactory.createUseBiometricsSwitch(
|
||||||
isEnabled = canUseBiometrics,
|
isChecked = state.useBiometricAuthentication,
|
||||||
onCheckedChange = ::onBiometricAuthenticationToggled,
|
isEnabled = canUseBiometrics,
|
||||||
).let(::add)
|
onCheckedChange = ::onBiometricAuthenticationToggled,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
itemsFactory.createRequireAccessCodeSwitch(
|
add(
|
||||||
isChecked = state.requireAccessCode,
|
itemsFactory.createRequireAccessCodeSwitch(
|
||||||
isEnabled = canUseBiometrics && state.useBiometricAuthentication,
|
isChecked = state.requireAccessCode,
|
||||||
onCheckedChange = ::onRequireAccessCodeToggled,
|
isEnabled = canUseBiometrics && state.useBiometricAuthentication,
|
||||||
).let(::add)
|
onCheckedChange = ::onRequireAccessCodeToggled,
|
||||||
|
),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
if (state.isBiometricsAvailable) {
|
if (state.isBiometricsAvailable) {
|
||||||
val canUseBiometrics = !state.needEnrollBiometrics && !state.isInProgress
|
val canUseBiometrics = !state.needEnrollBiometrics && !state.isInProgress
|
||||||
|
|
||||||
itemsFactory.createSaveWalletsSwitch(
|
add(
|
||||||
isChecked = state.saveWallets,
|
itemsFactory.createSaveWalletsSwitch(
|
||||||
isEnabled = canUseBiometrics,
|
isChecked = state.saveWallets,
|
||||||
onCheckedChange = ::onSaveWalletsToggled,
|
isEnabled = canUseBiometrics,
|
||||||
).let(::add)
|
onCheckedChange = ::onSaveWalletsToggled,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
itemsFactory.createSaveAccessCodeSwitch(
|
add(
|
||||||
isChecked = state.saveAccessCodes,
|
itemsFactory.createSaveAccessCodeSwitch(
|
||||||
isEnabled = canUseBiometrics,
|
isChecked = state.saveAccessCodes,
|
||||||
onCheckedChange = ::onSaveAccessCodesToggled,
|
isEnabled = canUseBiometrics,
|
||||||
).let(::add)
|
onCheckedChange = ::onSaveAccessCodesToggled,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
itemsFactory.createFlipToHideBalanceSwitch(
|
add(
|
||||||
isChecked = state.isHidingEnabled,
|
itemsFactory.createFlipToHideBalanceSwitch(
|
||||||
isEnabled = true,
|
isChecked = state.isHidingEnabled,
|
||||||
onCheckedChange = ::onFlipToHideBalanceToggled,
|
isEnabled = true,
|
||||||
).let(::add)
|
onCheckedChange = ::onFlipToHideBalanceToggled,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
itemsFactory.createSelectThemeModeButton(
|
add(
|
||||||
currentThemeMode = state.selectedThemeMode,
|
itemsFactory.createSelectThemeModeButton(
|
||||||
onClick = { showThemeModeSelector(state.selectedThemeMode) },
|
currentThemeMode = state.selectedThemeMode,
|
||||||
).let(::add)
|
onClick = { showThemeModeSelector(state.selectedThemeMode) },
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return items.toImmutableList()
|
return items.toImmutableList()
|
||||||
|
|
@ -280,7 +296,7 @@ internal class AppSettingsModel @Inject constructor(
|
||||||
val param = AnalyticsParam.OnOffState(enable)
|
val param = AnalyticsParam.OnOffState(enable)
|
||||||
analyticsEventHandler.send(Settings.AppSettings.HideBalanceChanged(param))
|
analyticsEventHandler.send(Settings.AppSettings.HideBalanceChanged(param))
|
||||||
|
|
||||||
store.dispatch(DetailsAction.AppSettings.ChangeBalanceHiding(hideBalance = enable))
|
store.dispatch(DetailsAction.AppSettings.ChangeBalanceHiding(shouldHideBalance = enable))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dismissDialog() {
|
private fun dismissDialog() {
|
||||||
|
|
@ -290,10 +306,10 @@ internal class AppSettingsModel @Inject constructor(
|
||||||
private fun bootstrapAppCurrencyUpdates() {
|
private fun bootstrapAppCurrencyUpdates() {
|
||||||
appCurrencyRepository
|
appCurrencyRepository
|
||||||
.getSelectedAppCurrency()
|
.getSelectedAppCurrency()
|
||||||
.onEach {
|
.onEach { appCurrency ->
|
||||||
if (it.code == store.state.globalState.appCurrency.code) return@onEach
|
if (appCurrency.code == store.state.globalState.appCurrency.code) return@onEach
|
||||||
|
|
||||||
store.dispatchWithMain(DetailsAction.AppSettings.ChangeAppCurrency(it))
|
store.dispatchWithMain(DetailsAction.AppSettings.ChangeAppCurrency(appCurrency))
|
||||||
}
|
}
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
.saveIn(appCurrencyUpdatesJobHolder)
|
.saveIn(appCurrencyUpdatesJobHolder)
|
||||||
|
|
|
||||||
|
|
@ -26,19 +26,19 @@ import com.tangem.wallet.R
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun CardSettingsScreen(state: CardSettingsScreenState, modifier: Modifier = Modifier) {
|
internal fun CardSettingsScreen(state: CardSettingsScreenState, modifier: Modifier = Modifier) {
|
||||||
val needReadCard = state.cardDetails == null
|
val isCardReadingNeeded = state.cardDetails == null
|
||||||
|
|
||||||
SettingsScreensScaffold(
|
SettingsScreensScaffold(
|
||||||
|
onBackClick = state.onBackClick,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
titleRes = R.string.card_settings_title,
|
||||||
content = {
|
content = {
|
||||||
if (needReadCard) {
|
if (isCardReadingNeeded) {
|
||||||
CardSettingsReadCard(state.onScanCardClick)
|
CardSettingsReadCard(state.onScanCardClick)
|
||||||
} else {
|
} else {
|
||||||
CardSettings(state = state)
|
CardSettings(state = state)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
titleRes = R.string.card_settings_title,
|
|
||||||
onBackClick = state.onBackClick,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,8 +123,8 @@ private fun CardSettings(state: CardSettingsScreenState) {
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag(DeviceSettingsScreenTestTags.LAZY_LIST),
|
.testTag(DeviceSettingsScreenTestTags.LAZY_LIST),
|
||||||
) {
|
) {
|
||||||
items(state.cardDetails) {
|
items(state.cardDetails) { cardInfo ->
|
||||||
val paddingBottom = when (it) {
|
val paddingBottom = when (cardInfo) {
|
||||||
is CardInfo.CardId, is CardInfo.Issuer -> TangemTheme.dimens.spacing12
|
is CardInfo.CardId, is CardInfo.Issuer -> TangemTheme.dimens.spacing12
|
||||||
is CardInfo.SignedHashes -> TangemTheme.dimens.spacing14
|
is CardInfo.SignedHashes -> TangemTheme.dimens.spacing14
|
||||||
is CardInfo.SecurityMode -> TangemTheme.dimens.spacing16
|
is CardInfo.SecurityMode -> TangemTheme.dimens.spacing16
|
||||||
|
|
@ -132,7 +132,7 @@ private fun CardSettings(state: CardSettingsScreenState) {
|
||||||
is CardInfo.AccessCodeRecovery -> TangemTheme.dimens.spacing16
|
is CardInfo.AccessCodeRecovery -> TangemTheme.dimens.spacing16
|
||||||
is CardInfo.ResetToFactorySettings -> TangemTheme.dimens.spacing28
|
is CardInfo.ResetToFactorySettings -> TangemTheme.dimens.spacing28
|
||||||
}
|
}
|
||||||
val paddingTop = when (it) {
|
val paddingTop = when (cardInfo) {
|
||||||
is CardInfo.CardId -> TangemTheme.dimens.spacing0
|
is CardInfo.CardId -> TangemTheme.dimens.spacing0
|
||||||
is CardInfo.Issuer -> TangemTheme.dimens.spacing12
|
is CardInfo.Issuer -> TangemTheme.dimens.spacing12
|
||||||
is CardInfo.SignedHashes -> TangemTheme.dimens.spacing12
|
is CardInfo.SignedHashes -> TangemTheme.dimens.spacing12
|
||||||
|
|
@ -145,8 +145,8 @@ private fun CardSettings(state: CardSettingsScreenState) {
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable(
|
.clickable(
|
||||||
enabled = it.clickable,
|
enabled = cardInfo.isClickable,
|
||||||
onClick = { state.onElementClick(it) },
|
onClick = { state.onElementClick(cardInfo) },
|
||||||
)
|
)
|
||||||
.padding(
|
.padding(
|
||||||
start = TangemTheme.dimens.spacing20,
|
start = TangemTheme.dimens.spacing20,
|
||||||
|
|
@ -155,25 +155,25 @@ private fun CardSettings(state: CardSettingsScreenState) {
|
||||||
top = paddingTop,
|
top = paddingTop,
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
val titleColor = if (it.clickable) {
|
val titleColor = if (cardInfo.isClickable) {
|
||||||
TangemTheme.colors.text.primary1
|
TangemTheme.colors.text.primary1
|
||||||
} else {
|
} else {
|
||||||
TangemTheme.colors.text.tertiary
|
TangemTheme.colors.text.tertiary
|
||||||
}
|
}
|
||||||
val subtitleColor = if (it.clickable) {
|
val subtitleColor = if (cardInfo.isClickable) {
|
||||||
TangemTheme.colors.text.secondary
|
TangemTheme.colors.text.secondary
|
||||||
} else {
|
} else {
|
||||||
TangemTheme.colors.text.tertiary
|
TangemTheme.colors.text.tertiary
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
text = it.titleRes.resolveReference(),
|
text = cardInfo.titleRes.resolveReference(),
|
||||||
color = titleColor,
|
color = titleColor,
|
||||||
style = TangemTheme.typography.subtitle1,
|
style = TangemTheme.typography.subtitle1,
|
||||||
modifier = Modifier.testTag(DeviceSettingsScreenTestTags.ITEM_TITLE),
|
modifier = Modifier.testTag(DeviceSettingsScreenTestTags.ITEM_TITLE),
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.size4))
|
Spacer(modifier = Modifier.size(TangemTheme.dimens.size4))
|
||||||
Text(
|
Text(
|
||||||
text = it.subtitle.resolveReference(),
|
text = cardInfo.subtitle.resolveReference(),
|
||||||
color = subtitleColor,
|
color = subtitleColor,
|
||||||
style = TangemTheme.typography.body2,
|
style = TangemTheme.typography.body2,
|
||||||
modifier = Modifier.testTag(DeviceSettingsScreenTestTags.ITEM_SUBTITLE),
|
modifier = Modifier.testTag(DeviceSettingsScreenTestTags.ITEM_SUBTITLE),
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ internal data class CardSettingsScreenState(
|
||||||
internal sealed class CardInfo(
|
internal sealed class CardInfo(
|
||||||
val titleRes: TextReference,
|
val titleRes: TextReference,
|
||||||
val subtitle: TextReference,
|
val subtitle: TextReference,
|
||||||
val clickable: Boolean = false,
|
val isClickable: Boolean = false,
|
||||||
) {
|
) {
|
||||||
class CardId(subtitle: String) : CardInfo(
|
class CardId(subtitle: String) : CardInfo(
|
||||||
titleRes = TextReference.Res(R.string.details_row_title_cid),
|
titleRes = TextReference.Res(R.string.details_row_title_cid),
|
||||||
|
|
@ -38,29 +38,29 @@ internal sealed class CardInfo(
|
||||||
class SecurityMode(securityOption: SecurityOption, clickable: Boolean) : CardInfo(
|
class SecurityMode(securityOption: SecurityOption, clickable: Boolean) : CardInfo(
|
||||||
titleRes = TextReference.Res(R.string.card_settings_security_mode),
|
titleRes = TextReference.Res(R.string.card_settings_security_mode),
|
||||||
subtitle = TextReference.Res(securityOption.toTitleRes()),
|
subtitle = TextReference.Res(securityOption.toTitleRes()),
|
||||||
clickable = clickable,
|
isClickable = clickable,
|
||||||
)
|
)
|
||||||
|
|
||||||
data object ChangeAccessCode : CardInfo(
|
data object ChangeAccessCode : CardInfo(
|
||||||
titleRes = TextReference.Res(R.string.card_settings_change_access_code),
|
titleRes = TextReference.Res(R.string.card_settings_change_access_code),
|
||||||
subtitle = TextReference.Res(R.string.card_settings_change_access_code_footer),
|
subtitle = TextReference.Res(R.string.card_settings_change_access_code_footer),
|
||||||
clickable = true,
|
isClickable = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
class AccessCodeRecovery(val enabled: Boolean) : CardInfo(
|
class AccessCodeRecovery(val isEnabled: Boolean) : CardInfo(
|
||||||
titleRes = TextReference.Res(R.string.card_settings_access_code_recovery_title),
|
titleRes = TextReference.Res(R.string.card_settings_access_code_recovery_title),
|
||||||
subtitle = if (enabled) {
|
subtitle = if (isEnabled) {
|
||||||
TextReference.Res(R.string.common_enabled)
|
TextReference.Res(R.string.common_enabled)
|
||||||
} else {
|
} else {
|
||||||
TextReference.Res(R.string.common_disabled)
|
TextReference.Res(R.string.common_disabled)
|
||||||
},
|
},
|
||||||
clickable = true,
|
isClickable = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
class ResetToFactorySettings(description: TextReference) : CardInfo(
|
class ResetToFactorySettings(description: TextReference) : CardInfo(
|
||||||
titleRes = TextReference.Res(R.string.card_settings_reset_card_to_factory),
|
titleRes = TextReference.Res(R.string.card_settings_reset_card_to_factory),
|
||||||
subtitle = description,
|
subtitle = description,
|
||||||
clickable = true,
|
isClickable = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ import com.tangem.wallet.R
|
||||||
@Composable
|
@Composable
|
||||||
fun AccessCodeRecoveryScreen(state: AccessCodeRecoveryScreenState, onBackClick: () -> Unit) {
|
fun AccessCodeRecoveryScreen(state: AccessCodeRecoveryScreenState, onBackClick: () -> Unit) {
|
||||||
SettingsScreensScaffold(
|
SettingsScreensScaffold(
|
||||||
content = { AccessCodeRecoveryOptions(state = state) },
|
|
||||||
onBackClick = onBackClick,
|
onBackClick = onBackClick,
|
||||||
|
content = { AccessCodeRecoveryOptions(state = state) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,13 +38,13 @@ fun AccessCodeRecoveryOptions(state: AccessCodeRecoveryScreenState) {
|
||||||
DetailsRadioButtonElement(
|
DetailsRadioButtonElement(
|
||||||
title = stringResourceSafe(id = R.string.common_enabled),
|
title = stringResourceSafe(id = R.string.common_enabled),
|
||||||
subtitle = stringResourceSafe(id = R.string.card_settings_access_code_recovery_enabled_description),
|
subtitle = stringResourceSafe(id = R.string.card_settings_access_code_recovery_enabled_description),
|
||||||
selected = state.enabledSelection,
|
isSelected = state.isEnabledSelection,
|
||||||
onClick = { state.onOptionClick(true) },
|
onClick = { state.onOptionClick(true) },
|
||||||
)
|
)
|
||||||
DetailsRadioButtonElement(
|
DetailsRadioButtonElement(
|
||||||
title = stringResourceSafe(id = R.string.common_disabled),
|
title = stringResourceSafe(id = R.string.common_disabled),
|
||||||
subtitle = stringResourceSafe(id = R.string.card_settings_access_code_recovery_disabled_description),
|
subtitle = stringResourceSafe(id = R.string.card_settings_access_code_recovery_disabled_description),
|
||||||
selected = !state.enabledSelection,
|
isSelected = !state.isEnabledSelection,
|
||||||
onClick = { state.onOptionClick(false) },
|
onClick = { state.onOptionClick(false) },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
package com.tangem.tap.features.details.ui.cardsettings.coderecovery
|
package com.tangem.tap.features.details.ui.cardsettings.coderecovery
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property enabledOnCard Indicates whether access code recovery is enabled on the card
|
* @property isEnabledOnCard Indicates whether access code recovery is enabled on the card
|
||||||
* @property enabledSelection Represents the currently selected option in the app (not yet saved on the card)
|
* @property isEnabledSelection Represents the currently selected option in the app (not yet saved on the card)
|
||||||
* @property isSaveChangesEnabled Determines if the user is allowed to save their selection to the card
|
* @property isSaveChangesEnabled Determines if the user is allowed to save their selection to the card
|
||||||
* @property onSaveChangesClick Callback function called when the user wants to apply the selected option
|
* @property onSaveChangesClick Callback function called when the user wants to apply the selected option
|
||||||
* @property onOptionClick Callback function called when the user selects an option
|
* @property onOptionClick Callback function called when the user selects an option
|
||||||
* */
|
* */
|
||||||
data class AccessCodeRecoveryScreenState(
|
data class AccessCodeRecoveryScreenState(
|
||||||
val enabledOnCard: Boolean,
|
val isEnabledOnCard: Boolean,
|
||||||
val enabledSelection: Boolean,
|
val isEnabledSelection: Boolean,
|
||||||
val isSaveChangesEnabled: Boolean,
|
val isSaveChangesEnabled: Boolean,
|
||||||
val onSaveChangesClick: () -> Unit,
|
val onSaveChangesClick: () -> Unit,
|
||||||
val onOptionClick: (Boolean) -> Unit,
|
val onOptionClick: (Boolean) -> Unit,
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@ internal class AccessCodeRecoveryModel @Inject constructor(
|
||||||
)
|
)
|
||||||
|
|
||||||
return AccessCodeRecoveryScreenState(
|
return AccessCodeRecoveryScreenState(
|
||||||
enabledOnCard = isEnabled,
|
isEnabledOnCard = isEnabled,
|
||||||
enabledSelection = isEnabled,
|
isEnabledSelection = isEnabled,
|
||||||
isSaveChangesEnabled = false,
|
isSaveChangesEnabled = false,
|
||||||
onSaveChangesClick = ::saveChanges,
|
onSaveChangesClick = ::saveChanges,
|
||||||
onOptionClick = ::selectOption,
|
onOptionClick = ::selectOption,
|
||||||
|
|
@ -52,7 +52,7 @@ internal class AccessCodeRecoveryModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveChanges() = modelScope.launch {
|
private fun saveChanges() = modelScope.launch {
|
||||||
val isEnabled = screenState.value.enabledSelection
|
val isEnabled = screenState.value.isEnabledSelection
|
||||||
|
|
||||||
tangemSdkManager
|
tangemSdkManager
|
||||||
.setAccessCodeRecoveryEnabled(scannedScanResponse.card.cardId, isEnabled)
|
.setAccessCodeRecoveryEnabled(scannedScanResponse.card.cardId, isEnabled)
|
||||||
|
|
@ -78,10 +78,10 @@ internal class AccessCodeRecoveryModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun selectOption(isEnabled: Boolean) {
|
private fun selectOption(isEnabled: Boolean) {
|
||||||
screenState.update {
|
screenState.update { state ->
|
||||||
it.copy(
|
state.copy(
|
||||||
enabledSelection = isEnabled,
|
isEnabledSelection = isEnabled,
|
||||||
isSaveChangesEnabled = isEnabled != it.enabledOnCard,
|
isSaveChangesEnabled = isEnabled != state.isEnabledOnCard,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ internal class CardSettingsInteractor @Inject constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun update(transform: (ScanResponse) -> ScanResponse) {
|
fun update(transform: (ScanResponse) -> ScanResponse) {
|
||||||
_scannedScanResponse.update {
|
_scannedScanResponse.update { scanResponse ->
|
||||||
requireNotNull(it)
|
requireNotNull(scanResponse)
|
||||||
transform(it)
|
transform(scanResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ internal class CardSettingsModel @Inject constructor(
|
||||||
|
|
||||||
private val params = paramsContainer.require<CardSettingsComponent.Params>()
|
private val params = paramsContainer.require<CardSettingsComponent.Params>()
|
||||||
|
|
||||||
private var previousBiometricsRequestPolicy: Boolean = false
|
private var isBiometricsRequestPolicyPrevious: Boolean = false
|
||||||
|
|
||||||
private val userWalletId = params.userWalletId
|
private val userWalletId = params.userWalletId
|
||||||
|
|
||||||
|
|
@ -77,13 +77,13 @@ internal class CardSettingsModel @Inject constructor(
|
||||||
// Reset card scanned data
|
// Reset card scanned data
|
||||||
cardSettingsInteractor.clear()
|
cardSettingsInteractor.clear()
|
||||||
// Restore the previous value of access code request policy
|
// Restore the previous value of access code request policy
|
||||||
cardSdkConfigRepository.isBiometricsRequestPolicy = previousBiometricsRequestPolicy
|
cardSdkConfigRepository.isBiometricsRequestPolicy = isBiometricsRequestPolicyPrevious
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateAccessCodeRequestPolicy() {
|
private fun updateAccessCodeRequestPolicy() {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
// !!!IMPORTANT!!!: Do not forget to restore the previous value in onCleared() method
|
// !!!IMPORTANT!!!: Do not forget to restore the previous value in onCleared() method
|
||||||
previousBiometricsRequestPolicy = cardSdkConfigRepository.isBiometricsRequestPolicy
|
isBiometricsRequestPolicyPrevious = cardSdkConfigRepository.isBiometricsRequestPolicy
|
||||||
|
|
||||||
val userWallet = getUserWalletUseCase(userWalletId)
|
val userWallet = getUserWalletUseCase(userWalletId)
|
||||||
.getOrElse { error("User wallet $userWalletId not found") }
|
.getOrElse { error("User wallet $userWalletId not found") }
|
||||||
|
|
@ -135,34 +135,38 @@ internal class CardSettingsModel @Inject constructor(
|
||||||
)
|
)
|
||||||
val isResetCardAllowed = isResetToFactoryAllowedByCard(card, cardTypesResolver)
|
val isResetCardAllowed = isResetToFactoryAllowedByCard(card, cardTypesResolver)
|
||||||
|
|
||||||
val cardDetails = buildList {
|
val cardDetails = buildList<CardInfo> {
|
||||||
CardInfo.CardId(cardId).let(::add)
|
add(CardInfo.CardId(cardId))
|
||||||
CardInfo.Issuer(card.issuer.name).let(::add)
|
add(CardInfo.Issuer(card.issuer.name))
|
||||||
|
|
||||||
if (!cardTypesResolver.isTangemTwins()) {
|
if (!cardTypesResolver.isTangemTwins()) {
|
||||||
CardInfo.SignedHashes(card.signedHashesCount().toString()).let(::add)
|
add(CardInfo.SignedHashes(card.signedHashesCount().toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
CardInfo.SecurityMode(
|
add(
|
||||||
currentSecurityOption,
|
CardInfo.SecurityMode(
|
||||||
clickable = allowedSecurityOptions.size > 1,
|
currentSecurityOption,
|
||||||
).let(::add)
|
clickable = allowedSecurityOptions.size > 1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
if (card.backupStatus?.isActive == true && card.isAccessCodeSet) {
|
if (card.backupStatus?.isActive == true && card.isAccessCodeSet) {
|
||||||
CardInfo.ChangeAccessCode.let(::add)
|
add(CardInfo.ChangeAccessCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAccessCodeRecoveryAllowed(cardTypesResolver)) {
|
if (isAccessCodeRecoveryAllowed(cardTypesResolver)) {
|
||||||
CardInfo.AccessCodeRecovery(isAccessCodeRecoveryEnabled(cardTypesResolver, card)).let(::add)
|
add(CardInfo.AccessCodeRecovery(isAccessCodeRecoveryEnabled(cardTypesResolver, card)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isResetCardAllowed) {
|
if (isResetCardAllowed) {
|
||||||
CardInfo.ResetToFactorySettings(
|
add(
|
||||||
description = getResetToFactoryDescription(
|
CardInfo.ResetToFactorySettings(
|
||||||
isActiveBackupStatus = card.backupStatus?.isActive == true,
|
description = getResetToFactoryDescription(
|
||||||
typesResolver = cardTypesResolver,
|
isActiveBackupStatus = card.backupStatus?.isActive == true,
|
||||||
|
typesResolver = cardTypesResolver,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
).let(::add)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@ import com.tangem.wallet.R
|
||||||
@Composable
|
@Composable
|
||||||
internal fun SettingsScreensScaffold(
|
internal fun SettingsScreensScaffold(
|
||||||
onBackClick: () -> Unit,
|
onBackClick: () -> Unit,
|
||||||
content: @Composable () -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
@StringRes titleRes: Int? = null,
|
@StringRes titleRes: Int? = null,
|
||||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
|
||||||
addBottomInsets: Boolean = true,
|
addBottomInsets: Boolean = true,
|
||||||
|
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||||
|
content: @Composable () -> Unit,
|
||||||
fab: @Composable () -> Unit = {},
|
fab: @Composable () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val backgroundColor = TangemTheme.colors.background.secondary
|
val backgroundColor = TangemTheme.colors.background.secondary
|
||||||
|
|
@ -129,18 +129,18 @@ internal fun DetailsMainButton(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun DetailsRadioButtonElement(title: String, subtitle: String, selected: Boolean, onClick: () -> Unit) {
|
internal fun DetailsRadioButtonElement(title: String, subtitle: String, isSelected: Boolean, onClick: () -> Unit) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.selectable(
|
.selectable(
|
||||||
selected = selected,
|
selected = isSelected,
|
||||||
onClick = { onClick() },
|
onClick = { onClick() },
|
||||||
)
|
)
|
||||||
.padding(start = 20.dp, end = 20.dp, top = 16.dp, bottom = 16.dp),
|
.padding(start = 20.dp, end = 20.dp, top = 16.dp, bottom = 16.dp),
|
||||||
) {
|
) {
|
||||||
RadioButton(
|
RadioButton(
|
||||||
selected = selected,
|
selected = isSelected,
|
||||||
onClick = null,
|
onClick = null,
|
||||||
modifier = Modifier.padding(end = 20.dp),
|
modifier = Modifier.padding(end = 20.dp),
|
||||||
colors = RadioButtonDefaults.colors(
|
colors = RadioButtonDefaults.colors(
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ internal fun isAccessCodeRecoveryAllowed(typeResolver: CardTypesResolver): Boole
|
||||||
|
|
||||||
internal fun isAccessCodeRecoveryEnabled(typeResolver: CardTypesResolver, card: CardDTO): Boolean =
|
internal fun isAccessCodeRecoveryEnabled(typeResolver: CardTypesResolver, card: CardDTO): Boolean =
|
||||||
if (typeResolver.isWallet2()) {
|
if (typeResolver.isWallet2()) {
|
||||||
card.userSettings?.isUserCodeRecoveryAllowed ?: false
|
card.userSettings?.isUserCodeRecoveryAllowed == true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
@ -27,11 +27,11 @@ import com.tangem.tap.features.details.ui.resetcard.ResetCardScreenState.Dialog
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ResetCardScreen(state: ResetCardScreenState, onBackClick: () -> Unit, modifier: Modifier = Modifier) {
|
internal fun ResetCardScreen(state: ResetCardScreenState, onBackClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||||
SettingsScreensScaffold(
|
SettingsScreensScaffold(
|
||||||
|
onBackClick = onBackClick,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
content = {
|
content = {
|
||||||
ResetCardView(state = state)
|
ResetCardView(state = state)
|
||||||
},
|
},
|
||||||
onBackClick = onBackClick,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
when (val dialog = state.dialog) {
|
when (val dialog = state.dialog) {
|
||||||
|
|
@ -65,7 +65,7 @@ private fun ResetCardView(state: ResetCardScreenState) {
|
||||||
Conditions(state)
|
Conditions(state)
|
||||||
DynamicSpacer(scrollState = scrollState)
|
DynamicSpacer(scrollState = scrollState)
|
||||||
SpacerH16()
|
SpacerH16()
|
||||||
ResetButton(enabled = state.resetButtonEnabled, onResetButtonClick = state.onResetButtonClick)
|
ResetButton(enabled = state.isResetButtonEnabled, onResetButtonClick = state.onResetButtonClick)
|
||||||
SpacerH16()
|
SpacerH16()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,18 +113,18 @@ private fun Description(text: TextReference) {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Conditions(state: ResetCardScreenState) {
|
private fun Conditions(state: ResetCardScreenState) {
|
||||||
state.warningsToShow.forEach {
|
state.warningsToShow.forEach { warning ->
|
||||||
when (it) {
|
when (warning) {
|
||||||
ResetCardScreenState.WarningsToReset.LOST_WALLET_ACCESS -> {
|
ResetCardScreenState.WarningsToReset.LOST_WALLET_ACCESS -> {
|
||||||
ConditionCheckBox(
|
ConditionCheckBox(
|
||||||
checkedState = state.acceptCondition1Checked,
|
checkedState = state.isAcceptCondition1Checked,
|
||||||
onCheckedChange = state.onAcceptCondition1ToggleClick,
|
onCheckedChange = state.onAcceptCondition1ToggleClick,
|
||||||
description = TextReference.Res(R.string.reset_card_to_factory_condition_1),
|
description = TextReference.Res(R.string.reset_card_to_factory_condition_1),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ResetCardScreenState.WarningsToReset.LOST_PASSWORD_RESTORE -> {
|
ResetCardScreenState.WarningsToReset.LOST_PASSWORD_RESTORE -> {
|
||||||
ConditionCheckBox(
|
ConditionCheckBox(
|
||||||
checkedState = state.acceptCondition2Checked,
|
checkedState = state.isAcceptCondition2Checked,
|
||||||
onCheckedChange = state.onAcceptCondition2ToggleClick,
|
onCheckedChange = state.onAcceptCondition2ToggleClick,
|
||||||
description = TextReference.Res(R.string.reset_card_to_factory_condition_2),
|
description = TextReference.Res(R.string.reset_card_to_factory_condition_2),
|
||||||
)
|
)
|
||||||
|
|
@ -238,12 +238,12 @@ private fun ResetCardScreenSample(modifier: Modifier = Modifier) {
|
||||||
) {
|
) {
|
||||||
ResetCardScreen(
|
ResetCardScreen(
|
||||||
state = ResetCardScreenState(
|
state = ResetCardScreenState(
|
||||||
resetButtonEnabled = true,
|
isResetButtonEnabled = true,
|
||||||
showResetPasswordButton = false,
|
isResetPasswordButtonShown = false,
|
||||||
warningsToShow = listOf(ResetCardScreenState.WarningsToReset.LOST_WALLET_ACCESS),
|
warningsToShow = listOf(ResetCardScreenState.WarningsToReset.LOST_WALLET_ACCESS),
|
||||||
descriptionText = TextReference.Res(R.string.reset_card_with_backup_to_factory_message),
|
descriptionText = TextReference.Res(R.string.reset_card_with_backup_to_factory_message),
|
||||||
acceptCondition1Checked = false,
|
isAcceptCondition1Checked = false,
|
||||||
acceptCondition2Checked = false,
|
isAcceptCondition2Checked = false,
|
||||||
onAcceptCondition1ToggleClick = {},
|
onAcceptCondition1ToggleClick = {},
|
||||||
onAcceptCondition2ToggleClick = {},
|
onAcceptCondition2ToggleClick = {},
|
||||||
onResetButtonClick = {},
|
onResetButtonClick = {},
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
|
|
||||||
internal data class ResetCardScreenState(
|
internal data class ResetCardScreenState(
|
||||||
val resetButtonEnabled: Boolean,
|
val isResetButtonEnabled: Boolean,
|
||||||
val descriptionText: TextReference,
|
val descriptionText: TextReference,
|
||||||
val warningsToShow: List<WarningsToReset>,
|
val warningsToShow: List<WarningsToReset>,
|
||||||
val showResetPasswordButton: Boolean,
|
val isResetPasswordButtonShown: Boolean,
|
||||||
val acceptCondition1Checked: Boolean,
|
val isAcceptCondition1Checked: Boolean,
|
||||||
val acceptCondition2Checked: Boolean,
|
val isAcceptCondition2Checked: Boolean,
|
||||||
val onAcceptCondition1ToggleClick: (Boolean) -> Unit,
|
val onAcceptCondition1ToggleClick: (Boolean) -> Unit,
|
||||||
val onAcceptCondition2ToggleClick: (Boolean) -> Unit,
|
val onAcceptCondition2ToggleClick: (Boolean) -> Unit,
|
||||||
val onResetButtonClick: () -> Unit,
|
val onResetButtonClick: () -> Unit,
|
||||||
|
|
|
||||||
|
|
@ -97,15 +97,15 @@ internal class ResetCardModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResetCardScreenState(
|
return ResetCardScreenState(
|
||||||
resetButtonEnabled = false,
|
isResetButtonEnabled = false,
|
||||||
descriptionText = getResetToFactoryDescription(
|
descriptionText = getResetToFactoryDescription(
|
||||||
isActiveBackupStatus = isActiveBackupPrimaryCard,
|
isActiveBackupStatus = isActiveBackupPrimaryCard,
|
||||||
typesResolver = currentCardTypesResolver,
|
typesResolver = currentCardTypesResolver,
|
||||||
),
|
),
|
||||||
warningsToShow = warningsToShow,
|
warningsToShow = warningsToShow,
|
||||||
showResetPasswordButton = shouldShowResetPasswordButton,
|
isResetPasswordButtonShown = shouldShowResetPasswordButton,
|
||||||
acceptCondition1Checked = false,
|
isAcceptCondition1Checked = false,
|
||||||
acceptCondition2Checked = false,
|
isAcceptCondition2Checked = false,
|
||||||
onAcceptCondition1ToggleClick = ::toggleFirstCondition,
|
onAcceptCondition1ToggleClick = ::toggleFirstCondition,
|
||||||
onAcceptCondition2ToggleClick = ::toggleSecondCondition,
|
onAcceptCondition2ToggleClick = ::toggleSecondCondition,
|
||||||
onResetButtonClick = { showDialog(ResetCardDialog.StartResetDialog) },
|
onResetButtonClick = { showDialog(ResetCardDialog.StartResetDialog) },
|
||||||
|
|
@ -121,26 +121,26 @@ internal class ResetCardModel @Inject constructor(
|
||||||
|
|
||||||
private fun toggleFirstCondition(isAccepted: Boolean) {
|
private fun toggleFirstCondition(isAccepted: Boolean) {
|
||||||
screenState.update { prevState ->
|
screenState.update { prevState ->
|
||||||
val resetButtonEnabled = if (prevState.showResetPasswordButton) {
|
val isResetButtonEnabled = if (prevState.isResetPasswordButtonShown) {
|
||||||
isAccepted && prevState.acceptCondition2Checked
|
isAccepted && prevState.isAcceptCondition2Checked
|
||||||
} else {
|
} else {
|
||||||
isAccepted
|
isAccepted
|
||||||
}
|
}
|
||||||
|
|
||||||
prevState.copy(
|
prevState.copy(
|
||||||
acceptCondition1Checked = isAccepted,
|
isAcceptCondition1Checked = isAccepted,
|
||||||
resetButtonEnabled = resetButtonEnabled,
|
isResetButtonEnabled = isResetButtonEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleSecondCondition(isAccepted: Boolean) {
|
private fun toggleSecondCondition(isAccepted: Boolean) {
|
||||||
screenState.update { prevState ->
|
screenState.update { prevState ->
|
||||||
val resetButtonEnabled = prevState.acceptCondition1Checked && isAccepted
|
val isResetButtonEnabled = prevState.isAcceptCondition1Checked && isAccepted
|
||||||
|
|
||||||
prevState.copy(
|
prevState.copy(
|
||||||
acceptCondition2Checked = isAccepted,
|
isAcceptCondition2Checked = isAccepted,
|
||||||
resetButtonEnabled = resetButtonEnabled,
|
isResetButtonEnabled = isResetButtonEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -183,14 +183,14 @@ internal class ResetCardModel @Inject constructor(
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
resetCardUseCase(cardId = primaryCardId, params = currentUserCodeParams).onRight {
|
resetCardUseCase(cardId = primaryCardId, params = currentUserCodeParams).onRight {
|
||||||
deleteSavedAccessCodesUseCase(cardId = primaryCardId)
|
deleteSavedAccessCodesUseCase(cardId = primaryCardId)
|
||||||
val hasUserWallets = deleteWalletUseCase(userWalletId = currentUserWalletId).getOrElse {
|
val hasUserWallets = deleteWalletUseCase(userWalletId = currentUserWalletId).getOrElse { error ->
|
||||||
Timber.e("Unable to delete user wallet: $it")
|
Timber.e("Unable to delete user wallet: $error")
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasUserWallets) {
|
if (hasUserWallets) {
|
||||||
val newSelectedWallet = getSelectedWalletSyncUseCase().getOrElse {
|
val newSelectedWallet = getSelectedWalletSyncUseCase().getOrElse { error ->
|
||||||
error("Failed to get selected wallet: $it")
|
error("Failed to get selected wallet: $error")
|
||||||
}
|
}
|
||||||
|
|
||||||
store.onUserWalletSelected(newSelectedWallet)
|
store.onUserWalletSelected(newSelectedWallet)
|
||||||
|
|
@ -269,7 +269,7 @@ internal class ResetCardModel @Inject constructor(
|
||||||
if (hotWalletFeatureToggles.isHotWalletEnabled) {
|
if (hotWalletFeatureToggles.isHotWalletEnabled) {
|
||||||
store.dispatchNavigationAction { replaceAll(AppRoute.Home()) }
|
store.dispatchNavigationAction { replaceAll(AppRoute.Home()) }
|
||||||
} else {
|
} else {
|
||||||
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync }.isSuccess
|
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLocked }.isSuccess
|
||||||
if (isLocked && userWalletsListManager.hasUserWallets) {
|
if (isLocked && userWalletsListManager.hasUserWallets) {
|
||||||
store.dispatchNavigationAction { popTo<AppRoute.Welcome>() }
|
store.dispatchNavigationAction { popTo<AppRoute.Welcome>() }
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,10 @@ internal fun SecurityModeScreen(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
SettingsScreensScaffold(
|
SettingsScreensScaffold(
|
||||||
|
onBackClick = onBackClick,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
content = { SecurityModeOptions(state = state) },
|
content = { SecurityModeOptions(state = state) },
|
||||||
// titleRes = R.string.card_settings_security_mode,
|
// titleRes = R.string.card_settings_security_mode,
|
||||||
onBackClick = onBackClick,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ private fun SecurityModeOptions(state: SecurityModeScreenState) {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SecurityOption(option: SecurityOption, state: SecurityModeScreenState) {
|
private fun SecurityOption(option: SecurityOption, state: SecurityModeScreenState) {
|
||||||
val selected = option == state.selectedSecurityMode
|
val isSelected = option == state.selectedSecurityMode
|
||||||
|
|
||||||
val title = option.toTitleRes()
|
val title = option.toTitleRes()
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ private fun SecurityOption(option: SecurityOption, state: SecurityModeScreenStat
|
||||||
DetailsRadioButtonElement(
|
DetailsRadioButtonElement(
|
||||||
title = stringResourceSafe(id = title),
|
title = stringResourceSafe(id = title),
|
||||||
subtitle = stringResourceSafe(id = subtitle),
|
subtitle = stringResourceSafe(id = subtitle),
|
||||||
selected = selected,
|
isSelected = isSelected,
|
||||||
onClick = { state.onNewModeSelected(option) },
|
onClick = { state.onNewModeSelected(option) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,9 @@ internal class SecurityModeModel @Inject constructor(
|
||||||
SecurityOption.AccessCode -> tangemSdkManager.setAccessCode(cardId)
|
SecurityOption.AccessCode -> tangemSdkManager.setAccessCode(cardId)
|
||||||
}
|
}
|
||||||
|
|
||||||
cardSettingsInteractor.update {
|
cardSettingsInteractor.update { scanResponse ->
|
||||||
it.copy(
|
scanResponse.copy(
|
||||||
card = it.card.copy(
|
card = scanResponse.card.copy(
|
||||||
isAccessCodeSet = selectedOption == SecurityOption.AccessCode,
|
isAccessCodeSet = selectedOption == SecurityOption.AccessCode,
|
||||||
isPasscodeSet = selectedOption == SecurityOption.PassCode,
|
isPasscodeSet = selectedOption == SecurityOption.PassCode,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ internal class MainViewModel @Inject constructor(
|
||||||
prepareSelectedWalletFeedback()
|
prepareSelectedWalletFeedback()
|
||||||
|
|
||||||
// await while initial route stack is initialized
|
// await while initial route stack is initialized
|
||||||
appRouterConfig.isInitialized.first { it }
|
appRouterConfig.initializedState.first { it }
|
||||||
|
|
||||||
isSplashScreenShown = false
|
isSplashScreenShown = false
|
||||||
}
|
}
|
||||||
|
|
@ -179,11 +179,9 @@ internal class MainViewModel @Inject constructor(
|
||||||
private fun prepareSelectedWalletFeedback() {
|
private fun prepareSelectedWalletFeedback() {
|
||||||
getSelectedWalletUseCase.invoke()
|
getSelectedWalletUseCase.invoke()
|
||||||
.mapLeft { emptyFlow<UserWallet>() }
|
.mapLeft { emptyFlow<UserWallet>() }
|
||||||
.onRight {
|
.onRight { wallet ->
|
||||||
it.distinctUntilChanged()
|
wallet.distinctUntilChanged()
|
||||||
.onEach { userWallet ->
|
.onEach { Analytics.setContext(it) }
|
||||||
Analytics.setContext(userWallet)
|
|
||||||
}
|
|
||||||
.flowOn(dispatchers.io)
|
.flowOn(dispatchers.io)
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
}
|
}
|
||||||
|
|
@ -208,7 +206,7 @@ internal class MainViewModel @Inject constructor(
|
||||||
return MoonPayService(
|
return MoonPayService(
|
||||||
apiKey = environmentConfig.moonPayApiKey,
|
apiKey = environmentConfig.moonPayApiKey,
|
||||||
secretKey = environmentConfig.moonPayApiSecretKey,
|
secretKey = environmentConfig.moonPayApiSecretKey,
|
||||||
logEnabled = LogConfig.network.moonPayService,
|
isLogEnabled = LogConfig.network.moonPayService,
|
||||||
userWalletProvider = { getSelectedWalletUseCase.sync().getOrNull() },
|
userWalletProvider = { getSelectedWalletUseCase.sync().getOrNull() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -224,8 +222,8 @@ internal class MainViewModel @Inject constructor(
|
||||||
.filter {
|
.filter {
|
||||||
it.isBalanceHidingNotificationEnabled && it.isBalanceHidden
|
it.isBalanceHidingNotificationEnabled && it.isBalanceHidden
|
||||||
}
|
}
|
||||||
.onEach {
|
.onEach { settings ->
|
||||||
if (!it.isUpdateFromToast) {
|
if (!settings.isUpdateFromToast) {
|
||||||
listenToFlipsUseCase.changeUpdateEnabled(false)
|
listenToFlipsUseCase.changeUpdateEnabled(false)
|
||||||
|
|
||||||
val message = BottomSheetMessage.invoke(
|
val message = BottomSheetMessage.invoke(
|
||||||
|
|
@ -354,6 +352,7 @@ internal class MainViewModel @Inject constructor(
|
||||||
listenToFlipsUseCase.changeUpdateEnabled(isUpdateEnabled = true)
|
listenToFlipsUseCase.changeUpdateEnabled(isUpdateEnabled = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("NullableToStringCall")
|
||||||
private fun sendKeyboardIdentifierEvent() {
|
private fun sendKeyboardIdentifierEvent() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val keyboardId = keyboardValidator.getKeyboardId()
|
val keyboardId = keyboardValidator.getKeyboardId()
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,11 @@ object OnboardingHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
response.cardTypesResolver.isWallet2() || response.cardTypesResolver.isShibaWallet() -> {
|
response.cardTypesResolver.isWallet2() || response.cardTypesResolver.isShibaWallet() -> {
|
||||||
val emptyWallets = response.card.wallets.isEmpty()
|
val areWalletsEmpty = response.card.wallets.isEmpty()
|
||||||
val activationInProgress = cardRepository.isActivationInProgress(cardId)
|
val isActivationInProgress = cardRepository.isActivationInProgress(cardId)
|
||||||
val isNoBackup = response.card.backupStatus == CardDTO.BackupStatus.NoBackup &&
|
val isNoBackup = response.card.backupStatus == CardDTO.BackupStatus.NoBackup &&
|
||||||
!DemoHelper.isDemoCard(response)
|
!DemoHelper.isDemoCard(response)
|
||||||
emptyWallets || activationInProgress || isNoBackup
|
areWalletsEmpty || isActivationInProgress || isNoBackup
|
||||||
}
|
}
|
||||||
|
|
||||||
response.card.wallets.isNotEmpty() -> cardRepository.isActivationInProgress(cardId)
|
response.card.wallets.isNotEmpty() -> cardRepository.isActivationInProgress(cardId)
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,8 @@ object TradeCryptoMiddleware {
|
||||||
fiatCurrencyName = action.appCurrencyCode,
|
fiatCurrencyName = action.appCurrencyCode,
|
||||||
walletAddress = networkAddress,
|
walletAddress = networkAddress,
|
||||||
isDarkTheme = MutableAppThemeModeHolder.isDarkThemeActive,
|
isDarkTheme = MutableAppThemeModeHolder.isDarkThemeActive,
|
||||||
)?.let {
|
)?.let { url ->
|
||||||
store.dispatchOpenUrl(it)
|
store.dispatchOpenUrl(url)
|
||||||
Analytics.send(Token.Withdraw.ScreenOpened())
|
Analytics.send(Token.Withdraw.ScreenOpened())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,8 @@ internal class WelcomeModel @Inject constructor(
|
||||||
|
|
||||||
this.state.update { prevState ->
|
this.state.update { prevState ->
|
||||||
prevState.copy(
|
prevState.copy(
|
||||||
showUnlockWithBiometricsProgress = state.isUnlockWithBiometricsInProgress,
|
isUnlockWithBiometricsProgressVisible = state.isUnlockWithBiometricsInProgress,
|
||||||
showUnlockWithCardProgress = state.isUnlockWithCardInProgress,
|
isUnlockWithCardProgressVisible = state.isUnlockWithCardInProgress,
|
||||||
warning = warning,
|
warning = warning,
|
||||||
error = state.error
|
error = state.error
|
||||||
?.takeIf { !it.silent && warning == null }
|
?.takeIf { !it.silent && warning == null }
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ internal sealed interface WelcomeAction : Action {
|
||||||
object ProceedWithCard : WelcomeAction {
|
object ProceedWithCard : WelcomeAction {
|
||||||
object Success : WelcomeAction
|
object Success : WelcomeAction
|
||||||
data class Error(val error: TangemError) : WelcomeAction
|
data class Error(val error: TangemError) : WelcomeAction
|
||||||
data class ChangeProgress(val showProgress: Boolean) : WelcomeAction
|
data class ChangeProgress(val isProgress: Boolean) : WelcomeAction
|
||||||
}
|
}
|
||||||
|
|
||||||
object CloseError : WelcomeAction
|
object CloseError : WelcomeAction
|
||||||
|
|
|
||||||
|
|
@ -141,13 +141,13 @@ internal class WelcomeMiddleware {
|
||||||
onSuccess = { scanResponse ->
|
onSuccess = { scanResponse ->
|
||||||
scope.launch { onCardScanned(scanResponse) }
|
scope.launch { onCardScanned(scanResponse) }
|
||||||
},
|
},
|
||||||
onFailure = {
|
onFailure = { error ->
|
||||||
when (it) {
|
when (error) {
|
||||||
is TangemSdkError.ExceptionError -> {
|
is TangemSdkError.ExceptionError -> {
|
||||||
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Success)
|
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Success)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Error(it))
|
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Error(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ internal object WelcomeReducer {
|
||||||
isUnlockWithCardInProgress = false,
|
isUnlockWithCardInProgress = false,
|
||||||
)
|
)
|
||||||
is WelcomeAction.ProceedWithCard.ChangeProgress -> state.copy(
|
is WelcomeAction.ProceedWithCard.ChangeProgress -> state.copy(
|
||||||
isUnlockWithCardInProgress = action.showProgress,
|
isUnlockWithCardInProgress = action.isProgress,
|
||||||
)
|
)
|
||||||
is WelcomeAction.ProceedWithBiometrics.Success -> state.copy(isUnlockWithBiometricsInProgress = false)
|
is WelcomeAction.ProceedWithBiometrics.Success -> state.copy(isUnlockWithBiometricsInProgress = false)
|
||||||
is WelcomeAction.ProceedWithCard.Success -> state.copy(isUnlockWithCardInProgress = false)
|
is WelcomeAction.ProceedWithCard.Success -> state.copy(isUnlockWithCardInProgress = false)
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import com.tangem.tap.features.welcome.ui.model.WarningModel
|
||||||
|
|
||||||
internal data class WelcomeScreenState(
|
internal data class WelcomeScreenState(
|
||||||
val onPopBack: () -> Unit = {},
|
val onPopBack: () -> Unit = {},
|
||||||
val showUnlockWithBiometricsProgress: Boolean = false,
|
val isUnlockWithBiometricsProgressVisible: Boolean = false,
|
||||||
val showUnlockWithCardProgress: Boolean = false,
|
val isUnlockWithCardProgressVisible: Boolean = false,
|
||||||
val warning: WarningModel? = null,
|
val warning: WarningModel? = null,
|
||||||
val error: TextReference? = null,
|
val error: TextReference? = null,
|
||||||
val onUnlockClick: () -> Unit = {},
|
val onUnlockClick: () -> Unit = {},
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ internal fun WelcomeScreen(state: WelcomeScreenState, modifier: Modifier = Modif
|
||||||
.systemBarsPadding(),
|
.systemBarsPadding(),
|
||||||
) {
|
) {
|
||||||
WelcomeScreenContent(
|
WelcomeScreenContent(
|
||||||
showUnlockProgress = state.showUnlockWithBiometricsProgress,
|
showUnlockProgress = state.isUnlockWithBiometricsProgressVisible,
|
||||||
showScanCardProgress = state.showUnlockWithCardProgress,
|
showScanCardProgress = state.isUnlockWithCardProgressVisible,
|
||||||
onUnlockClick = state.onUnlockClick,
|
onUnlockClick = state.onUnlockClick,
|
||||||
onScanCardClick = state.onScanCardClick,
|
onScanCardClick = state.onScanCardClick,
|
||||||
)
|
)
|
||||||
|
|
@ -57,8 +57,8 @@ internal fun WelcomeScreen(state: WelcomeScreenState, modifier: Modifier = Modif
|
||||||
WarningDialog(warning)
|
WarningDialog(warning)
|
||||||
|
|
||||||
LaunchedEffect(errorMessage, state.onCloseError) {
|
LaunchedEffect(errorMessage, state.onCloseError) {
|
||||||
errorMessage?.let {
|
errorMessage?.let { message ->
|
||||||
snackbarHostState.showSnackbar(it)
|
snackbarHostState.showSnackbar(message)
|
||||||
state.onCloseError()
|
state.onCloseError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,8 +82,8 @@ private class WelcomeComponentPreviewProvider : PreviewParameterProvider<Welcome
|
||||||
PreviewWelcomeComponent(),
|
PreviewWelcomeComponent(),
|
||||||
PreviewWelcomeComponent(
|
PreviewWelcomeComponent(
|
||||||
initialState = WelcomeScreenState(
|
initialState = WelcomeScreenState(
|
||||||
showUnlockWithBiometricsProgress = true,
|
isUnlockWithBiometricsProgressVisible = true,
|
||||||
showUnlockWithCardProgress = true,
|
isUnlockWithCardProgressVisible = true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PreviewWelcomeComponent(
|
PreviewWelcomeComponent(
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||||
internal class DefaultAuthProvider(
|
internal class DefaultAuthProvider(
|
||||||
private val userWalletsListManager: UserWalletsListManager,
|
private val userWalletsListManager: UserWalletsListManager,
|
||||||
private val userWalletsListRepository: UserWalletsListRepository,
|
private val userWalletsListRepository: UserWalletsListRepository,
|
||||||
private val useNewListRepository: Boolean = false,
|
private val shouldUseNewListRepository: Boolean = false,
|
||||||
) : AuthProvider {
|
) : AuthProvider {
|
||||||
|
|
||||||
override suspend fun getCardPublicKey(): String {
|
override suspend fun getCardPublicKey(): String {
|
||||||
|
|
@ -39,7 +39,7 @@ internal class DefaultAuthProvider(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getWallets(): List<UserWallet> {
|
private suspend fun getWallets(): List<UserWallet> {
|
||||||
return if (useNewListRepository) {
|
return if (shouldUseNewListRepository) {
|
||||||
userWalletsListRepository.userWalletsSync()
|
userWalletsListRepository.userWalletsSync()
|
||||||
} else {
|
} else {
|
||||||
userWalletsListManager.userWalletsSync
|
userWalletsListManager.userWalletsSync
|
||||||
|
|
@ -47,7 +47,7 @@ internal class DefaultAuthProvider(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getSelectedWallet(): UserWallet? {
|
private suspend fun getSelectedWallet(): UserWallet? {
|
||||||
return if (useNewListRepository) {
|
return if (shouldUseNewListRepository) {
|
||||||
userWalletsListRepository.selectedUserWalletSync()
|
userWalletsListRepository.selectedUserWalletSync()
|
||||||
} else {
|
} else {
|
||||||
userWalletsListManager.selectedUserWalletSync
|
userWalletsListManager.selectedUserWalletSync
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import java.util.concurrent.atomic.AtomicReference
|
||||||
|
|
||||||
internal class DefaultExpressAuthProvider : ExpressAuthProvider {
|
internal class DefaultExpressAuthProvider : ExpressAuthProvider {
|
||||||
|
|
||||||
private var uuid = AtomicReference(UUID.randomUUID())
|
private val uuid = AtomicReference(UUID.randomUUID())
|
||||||
|
|
||||||
override fun getSessionId(): String {
|
override fun getSessionId(): String {
|
||||||
return uuid.get().toString()
|
return uuid.get().toString()
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ internal class AuthModule {
|
||||||
return DefaultAuthProvider(
|
return DefaultAuthProvider(
|
||||||
userWalletsListManager = userWalletsListManager,
|
userWalletsListManager = userWalletsListManager,
|
||||||
userWalletsListRepository = userWalletsListRepository,
|
userWalletsListRepository = userWalletsListRepository,
|
||||||
useNewListRepository = hotWalletFeatureToggles.isHotWalletEnabled,
|
shouldUseNewListRepository = hotWalletFeatureToggles.isHotWalletEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ internal class DefaultRampManager(
|
||||||
sendUnavailabilityReason: ScenarioUnavailabilityReason?,
|
sendUnavailabilityReason: ScenarioUnavailabilityReason?,
|
||||||
): Either<ScenarioUnavailabilityReason, Unit> {
|
): Either<ScenarioUnavailabilityReason, Unit> {
|
||||||
return either {
|
return either {
|
||||||
val sellSupportedByService = catch(
|
val isSellSupportedByService = catch(
|
||||||
block = {
|
block = {
|
||||||
val serviceCurrency = cryptoCurrencyConverter.convertBack(status.currency)
|
val serviceCurrency = cryptoCurrencyConverter.convertBack(status.currency)
|
||||||
|
|
||||||
|
|
@ -78,7 +78,7 @@ internal class DefaultRampManager(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure(condition = sellSupportedByService) {
|
ensure(condition = isSellSupportedByService) {
|
||||||
ScenarioUnavailabilityReason.NotSupportedBySellService(status.currency.name)
|
ScenarioUnavailabilityReason.NotSupportedBySellService(status.currency.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ data class MoonPayUserStatus(
|
||||||
val stateCode: String,
|
val stateCode: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Suppress("BooleanPropertyNaming")
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class MoonPayCurrencies(
|
data class MoonPayCurrencies(
|
||||||
@Json(name = "type") val type: String,
|
@Json(name = "type") val type: String,
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import javax.crypto.spec.SecretKeySpec
|
||||||
class MoonPayService(
|
class MoonPayService(
|
||||||
private val apiKey: String,
|
private val apiKey: String,
|
||||||
private val secretKey: String,
|
private val secretKey: String,
|
||||||
private val logEnabled: Boolean,
|
private val isLogEnabled: Boolean,
|
||||||
private val userWalletProvider: () -> UserWallet?,
|
private val userWalletProvider: () -> UserWallet?,
|
||||||
) : ExchangeService {
|
) : ExchangeService {
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ class MoonPayService(
|
||||||
private val api: MoonPayApi by lazy {
|
private val api: MoonPayApi by lazy {
|
||||||
createRetrofitInstance(
|
createRetrofitInstance(
|
||||||
baseUrl = MoonPayApi.MOOONPAY_BASE_URL,
|
baseUrl = MoonPayApi.MOOONPAY_BASE_URL,
|
||||||
logEnabled = logEnabled,
|
logEnabled = isLogEnabled,
|
||||||
).create(MoonPayApi::class.java)
|
).create(MoonPayApi::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,24 +104,35 @@ class MoonPayService(
|
||||||
|
|
||||||
override fun availableForSell(currency: Currency): Boolean {
|
override fun availableForSell(currency: Currency): Boolean {
|
||||||
val userWallet = userWalletProvider() ?: return false
|
val userWallet = userWalletProvider() ?: return false
|
||||||
val checkCardExchange = userWallet !is UserWallet.Cold || !userWallet.scanResponse.card.isStart2Coin
|
val isExchangeSupported = userWallet !is UserWallet.Cold || !userWallet.scanResponse.card.isStart2Coin
|
||||||
|
|
||||||
if (!checkCardExchange) return false
|
if (!isExchangeSupported) return false
|
||||||
|
|
||||||
if (!isSellAllowed()) return false
|
if (!isSellAllowed()) return false
|
||||||
|
|
||||||
val availableForSell = status?.availableForSell ?: return false
|
val availableForSell = status?.availableForSell ?: return false
|
||||||
|
|
||||||
val supportedCurrency = currency.blockchain.moonPaySupportedCurrency ?: return false
|
val supportedCurrency = currency.blockchain.moonPaySupportedCurrency ?: return false
|
||||||
return availableForSell.any {
|
return availableForSell.any { availableCurrency ->
|
||||||
when (currency) {
|
when (currency) {
|
||||||
is Currency.Blockchain -> {
|
is Currency.Blockchain -> {
|
||||||
it.networkCode.equals(other = supportedCurrency.networkCode, ignoreCase = true) &&
|
availableCurrency.networkCode.equals(
|
||||||
it.currencyCode.equals(other = supportedCurrency.currencyCode, ignoreCase = true)
|
other = supportedCurrency.networkCode,
|
||||||
|
ignoreCase = true,
|
||||||
|
) && availableCurrency.currencyCode.equals(
|
||||||
|
other = supportedCurrency.currencyCode,
|
||||||
|
ignoreCase = true,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is Currency.Token -> {
|
is Currency.Token -> {
|
||||||
it.networkCode.equals(other = supportedCurrency.networkCode, ignoreCase = true) &&
|
availableCurrency.networkCode.equals(
|
||||||
it.contractAddress.equals(other = currency.token.contractAddress, ignoreCase = true)
|
other = supportedCurrency.networkCode,
|
||||||
|
ignoreCase = true,
|
||||||
|
) &&
|
||||||
|
availableCurrency.contractAddress.equals(
|
||||||
|
other = currency.token.contractAddress,
|
||||||
|
ignoreCase = true,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -137,15 +148,18 @@ class MoonPayService(
|
||||||
if (blockchain.isTestnet()) return blockchain.getTestnetTopUpUrl()
|
if (blockchain.isTestnet()) return blockchain.getTestnetTopUpUrl()
|
||||||
|
|
||||||
val supportedCurrency = blockchain.moonPaySupportedCurrency ?: return null
|
val supportedCurrency = blockchain.moonPaySupportedCurrency ?: return null
|
||||||
val moonpayCurrency = status?.availableForSell?.firstOrNull {
|
val moonpayCurrency = status?.availableForSell?.firstOrNull { availableCurrency ->
|
||||||
when (cryptoCurrency) {
|
when (cryptoCurrency) {
|
||||||
is CryptoCurrency.Coin -> {
|
is CryptoCurrency.Coin -> {
|
||||||
it.networkCode.equals(other = supportedCurrency.networkCode, ignoreCase = true) &&
|
availableCurrency.networkCode.equals(other = supportedCurrency.networkCode, ignoreCase = true) &&
|
||||||
it.currencyCode.equals(other = supportedCurrency.currencyCode, ignoreCase = true)
|
availableCurrency.currencyCode.equals(other = supportedCurrency.currencyCode, ignoreCase = true)
|
||||||
}
|
}
|
||||||
is CryptoCurrency.Token -> {
|
is CryptoCurrency.Token -> {
|
||||||
it.networkCode.equals(other = supportedCurrency.networkCode, ignoreCase = true) &&
|
availableCurrency.networkCode.equals(other = supportedCurrency.networkCode, ignoreCase = true) &&
|
||||||
it.contractAddress.equals(other = cryptoCurrency.contractAddress, ignoreCase = true)
|
availableCurrency.contractAddress.equals(
|
||||||
|
other = cryptoCurrency.contractAddress,
|
||||||
|
ignoreCase = true,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: return null
|
} ?: return null
|
||||||
|
|
@ -184,7 +198,7 @@ class MoonPayService(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isSellAllowed(): Boolean {
|
private fun isSellAllowed(): Boolean {
|
||||||
return status?.responseUserStatus?.isSellAllowed ?: false
|
return status?.responseUserStatus?.isSellAllowed == true
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,13 @@ class UserWalletManagerImpl(
|
||||||
override suspend fun getNativeTokenBalance(networkId: String, derivationPath: String?): ProxyAmount? {
|
override suspend fun getNativeTokenBalance(networkId: String, derivationPath: String?): ProxyAmount? {
|
||||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
||||||
val walletManager = getActualWalletManager(blockchain, derivationPath)
|
val walletManager = getActualWalletManager(blockchain, derivationPath)
|
||||||
return walletManager.wallet.amounts.firstNotNullOfOrNull {
|
return walletManager.wallet.amounts.firstNotNullOfOrNull { amountEntry ->
|
||||||
it.takeIf { it.key is AmountType.Coin }
|
amountEntry.takeIf { amountEntry.key is AmountType.Coin }
|
||||||
}?.value?.let {
|
}?.value?.let { amount ->
|
||||||
ProxyAmount(
|
ProxyAmount(
|
||||||
it.currencySymbol,
|
amount.currencySymbol,
|
||||||
it.value ?: BigDecimal.ZERO,
|
amount.value ?: BigDecimal.ZERO,
|
||||||
it.decimals,
|
amount.decimals,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,17 +34,17 @@ import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.tap.routing.component.RoutingComponent
|
import com.tangem.tap.routing.component.RoutingComponent
|
||||||
import com.tangem.tap.routing.transitions.RoutingTransitionAnimationFactory
|
import com.tangem.tap.routing.transitions.RoutingTransitionAnimationFactory
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList", "ReusedModifierInstance")
|
||||||
@OptIn(ExperimentalDecomposeApi::class)
|
@OptIn(ExperimentalDecomposeApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
internal fun RootContent(
|
internal fun RootContent(
|
||||||
stack: Value<ChildStack<AppRoute, RoutingComponent.Child>>,
|
stack: Value<ChildStack<AppRoute, RoutingComponent.Child>>,
|
||||||
backHandler: BackHandler,
|
backHandler: BackHandler,
|
||||||
uiDependencies: UiDependencies,
|
uiDependencies: UiDependencies,
|
||||||
wcContent: @Composable (modifier: Modifier) -> Unit,
|
|
||||||
hotAccessCodeContent: @Composable (modifier: Modifier) -> Unit,
|
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
wcContent: @Composable (modifier: Modifier) -> Unit,
|
||||||
|
hotAccessCodeContent: @Composable (modifier: Modifier) -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
||||||
AppRoute.Wallet
|
AppRoute.Wallet
|
||||||
}
|
}
|
||||||
}.also {
|
}.also {
|
||||||
appRouterConfig.isInitialized.value = true
|
appRouterConfig.initializedState.value = true
|
||||||
checkForUnfinishedBackup()
|
checkForUnfinishedBackup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -141,13 +141,13 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
RootContent(
|
RootContent(
|
||||||
modifier = modifier,
|
|
||||||
stack = stack,
|
stack = stack,
|
||||||
|
backHandler = backHandler,
|
||||||
uiDependencies = uiDependencies,
|
uiDependencies = uiDependencies,
|
||||||
|
onBack = router::pop,
|
||||||
|
modifier = modifier,
|
||||||
wcContent = { wcRoutingComponent.Content(it) },
|
wcContent = { wcRoutingComponent.Content(it) },
|
||||||
hotAccessCodeContent = { hotAccessCodeRequestComponent.Content(it) },
|
hotAccessCodeContent = { hotAccessCodeRequestComponent.Content(it) },
|
||||||
backHandler = backHandler,
|
|
||||||
onBack = router::pop,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ internal interface AppRouterConfig {
|
||||||
var routerScope: CoroutineScope?
|
var routerScope: CoroutineScope?
|
||||||
var componentRouter: Router?
|
var componentRouter: Router?
|
||||||
var stack: List<AppRoute>?
|
var stack: List<AppRoute>?
|
||||||
val isInitialized: MutableStateFlow<Boolean>
|
val initializedState: MutableStateFlow<Boolean>
|
||||||
|
|
||||||
// TODO: Replace with UI message handler: [REDACTED_JIRA]
|
// TODO: Replace with UI message handler: [REDACTED_JIRA]
|
||||||
var snackbarHandler: SnackbarHandler?
|
var snackbarHandler: SnackbarHandler?
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,5 @@ internal class MutableAppRouterConfig : AppRouterConfig {
|
||||||
override var componentRouter: Router? = null
|
override var componentRouter: Router? = null
|
||||||
override var stack: List<AppRoute>? = null
|
override var stack: List<AppRoute>? = null
|
||||||
override var snackbarHandler: SnackbarHandler? = null
|
override var snackbarHandler: SnackbarHandler? = null
|
||||||
override val isInitialized: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
override val initializedState: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||||
}
|
}
|
||||||
|
|
@ -4,13 +4,10 @@ import androidx.compose.animation.core.CubicBezierEasing
|
||||||
import androidx.compose.animation.core.FiniteAnimationSpec
|
import androidx.compose.animation.core.FiniteAnimationSpec
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.scale
|
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.layout.layout
|
import androidx.compose.ui.layout.layout
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.animation.*
|
import com.arkivanov.decompose.extensions.compose.stack.animation.*
|
||||||
import com.tangem.common.routing.AppRoute
|
import com.tangem.common.routing.AppRoute
|
||||||
import kotlin.compareTo
|
|
||||||
import kotlin.times
|
|
||||||
|
|
||||||
object RoutingTransitionAnimationFactory {
|
object RoutingTransitionAnimationFactory {
|
||||||
|
|
||||||
|
|
@ -58,7 +55,7 @@ object RoutingTransitionAnimationFactory {
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
private fun slideAndFade(directions: Set<Direction>? = null): StackAnimator {
|
private fun slideAndFade(directions: Set<Direction>? = null): StackAnimator {
|
||||||
val easing = CubicBezierEasing(0.55f, 0.0f, 0.0f, 1f)
|
val easing = CubicBezierEasing(a = 0.55f, b = 0.0f, c = 0.0f, d = 1f)
|
||||||
|
|
||||||
return stackAnimator(
|
return stackAnimator(
|
||||||
animationSpec = tween(durationMillis = 400, easing = easing),
|
animationSpec = tween(durationMillis = 400, easing = easing),
|
||||||
|
|
|
||||||
|
|
@ -183,10 +183,10 @@ internal class ChildFactory @Inject constructor(
|
||||||
token = route.token,
|
token = route.token,
|
||||||
appCurrency = route.appCurrency,
|
appCurrency = route.appCurrency,
|
||||||
showPortfolio = route.showPortfolio,
|
showPortfolio = route.showPortfolio,
|
||||||
analyticsParams = route.analyticsParams?.let {
|
analyticsParams = route.analyticsParams?.let { params ->
|
||||||
MarketsTokenDetailsComponent.AnalyticsParams(
|
MarketsTokenDetailsComponent.AnalyticsParams(
|
||||||
blockchain = it.blockchain,
|
blockchain = params.blockchain,
|
||||||
source = it.source,
|
source = params.source,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -311,7 +311,6 @@ private fun MarketChartPreview(
|
||||||
}
|
}
|
||||||
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val look by dataProducer.lookState.collectAsState()
|
|
||||||
|
|
||||||
TangemThemePreview {
|
TangemThemePreview {
|
||||||
val growingColor = TangemTheme.colors.icon.accent
|
val growingColor = TangemTheme.colors.icon.accent
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue