Updated on 2026-08-14
This commit is contained in:
commit
da717845f0
538 changed files with 7350 additions and 5597 deletions
|
|
@ -28,7 +28,7 @@ import androidx.lifecycle.flowWithLifecycle
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import arrow.core.getOrElse
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.arkivanov.decompose.value.observe
|
||||
import com.arkivanov.decompose.value.subscribe
|
||||
import com.arkivanov.essenty.lifecycle.asEssentyLifecycle
|
||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
|
@ -46,6 +46,7 @@ import com.tangem.core.ui.message.EventMessageEffect
|
|||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.data.balancehiding.DefaultDeviceFlipDetector
|
||||
import com.tangem.data.card.sdk.CardSdkOwner
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
|
|
@ -59,14 +60,9 @@ import com.tangem.domain.staking.SendUnsubmittedHashesUseCase
|
|||
import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
|
||||
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
|
||||
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
||||
import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter
|
||||
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
|
||||
import com.tangem.features.wallet.navigation.WalletRouter
|
||||
import com.tangem.google.GoogleServicesHelper
|
||||
import com.tangem.operations.backup.BackupService
|
||||
import com.tangem.sdk.api.BackupServiceHolder
|
||||
|
|
@ -138,21 +134,9 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
@Inject
|
||||
lateinit var scanCardUseCase: ScanCardUseCase
|
||||
|
||||
@Inject
|
||||
lateinit var walletRouter: WalletRouter
|
||||
|
||||
@Inject
|
||||
lateinit var tokenDetailsRouter: TokenDetailsRouter
|
||||
|
||||
@Inject
|
||||
lateinit var walletConnectInteractor: WalletConnectInteractor
|
||||
|
||||
@Inject
|
||||
lateinit var sendRouter: SendRouter
|
||||
|
||||
@Inject
|
||||
lateinit var qrScanningRouter: QrScanningRouter
|
||||
|
||||
@Inject
|
||||
lateinit var deepLinksRegistry: DeepLinksRegistry
|
||||
|
||||
|
|
@ -187,9 +171,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
@Inject
|
||||
internal lateinit var routingComponentFactory: RoutingComponent.Factory
|
||||
|
||||
@Inject
|
||||
lateinit var pushNotificationsRouter: PushNotificationsRouter
|
||||
|
||||
@Inject
|
||||
lateinit var cardRepository: CardRepository
|
||||
|
||||
|
|
@ -217,6 +198,9 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
@Inject
|
||||
internal lateinit var uiDependencies: UiDependencies
|
||||
|
||||
@Inject
|
||||
internal lateinit var defaultDeviceFlipDetector: DefaultDeviceFlipDetector
|
||||
|
||||
internal val viewModel: MainViewModel by viewModels()
|
||||
|
||||
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode>
|
||||
|
|
@ -283,6 +267,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
}
|
||||
|
||||
lifecycle.addObserver(WindowObscurationObserver)
|
||||
lifecycle.addObserver(defaultDeviceFlipDetector)
|
||||
}
|
||||
|
||||
private fun installEventMessageEffect() {
|
||||
|
|
@ -331,12 +316,12 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
appRouterConfig.componentRouter = routingComponent.router
|
||||
appRouterConfig.snackbarHandler = this
|
||||
|
||||
routingComponent.stack.observe(lifecycle.asEssentyLifecycle()) { childStack ->
|
||||
routingComponent.stack.subscribe(lifecycle.asEssentyLifecycle()) { childStack ->
|
||||
val stack = childStack.backStack
|
||||
.plus(childStack.active)
|
||||
.map { it.configuration }
|
||||
|
||||
if (stack == appRouterConfig.stack) return@observe
|
||||
if (stack == appRouterConfig.stack) return@subscribe
|
||||
|
||||
appRouterConfig.stack = stack
|
||||
|
||||
|
|
|
|||
|
|
@ -1,152 +0,0 @@
|
|||
package com.tangem.tap.common.compose
|
||||
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.interaction.InteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsFocusedAsState
|
||||
import androidx.compose.material.TextFieldColors
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
// Copy from com.tangem.core.ui.components
|
||||
// TODO: Delete this after fields has been moved to core-ui module
|
||||
internal object TangemTextFieldsDefault {
|
||||
val defaultTextFieldColors: TangemTextFieldColors
|
||||
@Composable @Stable get() = TangemTextFieldColors(
|
||||
textColor = TangemTheme.colors.text.primary1,
|
||||
disabledTextColor = TangemTheme.colors.text.disabled,
|
||||
backgroundColor = Color.Transparent,
|
||||
cursorColor = TangemTheme.colors.icon.primary1,
|
||||
errorCursorColor = TangemTheme.colors.icon.warning,
|
||||
focusedIndicatorColor = TangemTheme.colors.icon.primary1,
|
||||
unfocusedIndicatorColor = TangemTheme.colors.stroke.primary,
|
||||
disabledIndicatorColor = TangemTheme.colors.stroke.primary,
|
||||
errorIndicatorColor = TangemTheme.colors.icon.warning,
|
||||
leadingIconColor = TangemTheme.colors.icon.informative,
|
||||
disabledLeadingIconColor = Color.Transparent,
|
||||
errorLeadingIconColor = TangemTheme.colors.icon.warning,
|
||||
trailingIconColor = TangemTheme.colors.icon.informative,
|
||||
disabledTrailingIconColor = Color.Transparent,
|
||||
errorTrailingIconColor = TangemTheme.colors.icon.warning,
|
||||
focusedLabelColor = TangemTheme.colors.text.primary1,
|
||||
unfocusedLabelColor = TangemTheme.colors.text.secondary,
|
||||
disabledLabelColor = TangemTheme.colors.text.disabled,
|
||||
errorLabelColor = TangemTheme.colors.icon.warning,
|
||||
placeholderColor = TangemTheme.colors.text.secondary,
|
||||
disabledPlaceholderColor = TangemTheme.colors.text.disabled,
|
||||
captionColor = TangemTheme.colors.text.tertiary,
|
||||
disabledCaptionColor = TangemTheme.colors.text.disabled,
|
||||
errorCaptionColor = TangemTheme.colors.icon.warning,
|
||||
)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal data class TangemTextFieldColors(
|
||||
private val textColor: Color,
|
||||
private val disabledTextColor: Color,
|
||||
private val cursorColor: Color,
|
||||
private val errorCursorColor: Color,
|
||||
private val focusedIndicatorColor: Color,
|
||||
private val unfocusedIndicatorColor: Color,
|
||||
private val errorIndicatorColor: Color,
|
||||
private val disabledIndicatorColor: Color,
|
||||
private val leadingIconColor: Color,
|
||||
private val disabledLeadingIconColor: Color,
|
||||
private val errorLeadingIconColor: Color,
|
||||
private val trailingIconColor: Color,
|
||||
private val disabledTrailingIconColor: Color,
|
||||
private val errorTrailingIconColor: Color,
|
||||
private val backgroundColor: Color,
|
||||
private val focusedLabelColor: Color,
|
||||
private val unfocusedLabelColor: Color,
|
||||
private val disabledLabelColor: Color,
|
||||
private val errorLabelColor: Color,
|
||||
private val placeholderColor: Color,
|
||||
private val disabledPlaceholderColor: Color,
|
||||
private val captionColor: Color,
|
||||
private val disabledCaptionColor: Color,
|
||||
private val errorCaptionColor: Color,
|
||||
) : TextFieldColors {
|
||||
|
||||
@Composable
|
||||
override fun leadingIconColor(enabled: Boolean, isError: Boolean): State<Color> {
|
||||
return rememberUpdatedState(
|
||||
when {
|
||||
!enabled -> disabledLeadingIconColor
|
||||
isError -> errorLeadingIconColor
|
||||
else -> leadingIconColor
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun trailingIconColor(enabled: Boolean, isError: Boolean): State<Color> {
|
||||
return rememberUpdatedState(
|
||||
when {
|
||||
!enabled -> disabledTrailingIconColor
|
||||
isError -> errorTrailingIconColor
|
||||
else -> trailingIconColor
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun indicatorColor(
|
||||
enabled: Boolean,
|
||||
isError: Boolean,
|
||||
interactionSource: InteractionSource,
|
||||
): State<Color> {
|
||||
val focused by interactionSource.collectIsFocusedAsState()
|
||||
|
||||
val targetValue = when {
|
||||
!enabled -> disabledIndicatorColor
|
||||
isError -> errorIndicatorColor
|
||||
focused -> focusedIndicatorColor
|
||||
else -> unfocusedIndicatorColor
|
||||
}
|
||||
return if (enabled) {
|
||||
animateColorAsState(targetValue, tween(durationMillis = 120))
|
||||
} else {
|
||||
rememberUpdatedState(targetValue)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun backgroundColor(enabled: Boolean): State<Color> {
|
||||
return rememberUpdatedState(backgroundColor)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun placeholderColor(enabled: Boolean): State<Color> {
|
||||
return rememberUpdatedState(if (enabled) placeholderColor else disabledPlaceholderColor)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun labelColor(enabled: Boolean, error: Boolean, interactionSource: InteractionSource): State<Color> {
|
||||
val focused by interactionSource.collectIsFocusedAsState()
|
||||
|
||||
val targetValue = when {
|
||||
!enabled -> disabledLabelColor
|
||||
error -> errorLabelColor
|
||||
focused -> focusedLabelColor
|
||||
else -> unfocusedLabelColor
|
||||
}
|
||||
return rememberUpdatedState(targetValue)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun textColor(enabled: Boolean): State<Color> {
|
||||
return rememberUpdatedState(if (enabled) textColor else disabledTextColor)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun cursorColor(isError: Boolean): State<Color> {
|
||||
return rememberUpdatedState(if (isError) errorCursorColor else cursorColor)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import android.widget.TextSwitcher
|
||||
import android.widget.TextView
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
fun TextView.update(text: String?) {
|
||||
if (this.text?.toString() != text) this.text = text
|
||||
}
|
||||
|
||||
fun EditText.update(text: String?) {
|
||||
if (this.text?.toString() == text) return
|
||||
|
||||
val textLength = text?.length ?: 0
|
||||
|
||||
// prevent cursor jumping while editing a text
|
||||
val cursorPosition = if (selectionEnd > textLength) textLength else selectionEnd
|
||||
this.setText(text)
|
||||
if (!isFocused || textLength == 0) return
|
||||
|
||||
if (cursorPosition == 0) setSelection(textLength) else setSelection(cursorPosition)
|
||||
}
|
||||
|
||||
fun EditText.setOnImeActionListener(action: Int, handler: (EditText) -> Unit) {
|
||||
this.setOnEditorActionListener { view, actionId, event ->
|
||||
if (actionId == action) {
|
||||
handler.invoke(this)
|
||||
return@setOnEditorActionListener true
|
||||
}
|
||||
return@setOnEditorActionListener false
|
||||
}
|
||||
}
|
||||
|
||||
fun TextSwitcher.update(text: CharSequence?) {
|
||||
val textView = this.currentView as? TextView ?: return
|
||||
|
||||
if (textView.text?.toString() != text?.toString()) this.setText(text)
|
||||
}
|
||||
|
||||
// By default the TextInputLayout didn't activates the error state if the message is empty or null
|
||||
fun TextInputLayout.enableError(enable: Boolean, errorMessage: String? = null) {
|
||||
if (enable) {
|
||||
if (errorMessage == null || errorMessage.isEmpty()) {
|
||||
error = "Any message"
|
||||
if (childCount == 2) getChildAt(1).visibility = View.GONE
|
||||
} else {
|
||||
error = errorMessage
|
||||
}
|
||||
} else {
|
||||
error = null
|
||||
isErrorEnabled = false
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import com.arkivanov.decompose.defaultComponentContext
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.DefaultAppComponentContext
|
||||
import com.tangem.core.decompose.di.DecomposeComponent
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.di.GlobalUiMessageSender
|
||||
import com.tangem.core.decompose.di.RootAppComponentContext
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
|
|
@ -27,7 +27,7 @@ internal object RootAppComponentContextModule {
|
|||
fun provideRootAppComponentContext(
|
||||
@ActivityContext context: Context,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
componentBuilder: DecomposeComponent.Builder,
|
||||
componentBuilder: ModelComponent.Builder,
|
||||
@GlobalUiMessageSender messageSender: UiMessageSender,
|
||||
): AppComponentContext {
|
||||
return DefaultAppComponentContext(
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import com.tangem.domain.analytics.repository.AnalyticsRepository
|
|||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object AnalyticsDomainModule {
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import com.tangem.blockchain.common.Wallet
|
|||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.domain.card.models.TwinKey
|
||||
import com.tangem.domain.models.scan.isRing
|
||||
import com.tangem.operations.sign.SignData
|
||||
import com.tangem.tap.domain.tasks.MultiSignHashTask
|
||||
import com.tangem.tap.domain.tasks.SignHashesTask
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlin.coroutines.resume
|
||||
|
|
@ -64,6 +66,40 @@ class TangemSigner(
|
|||
is CompletionResult.Failure -> CompletionResult.Failure(result.error)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun multiSign(
|
||||
dataToSign: List<SignData>,
|
||||
publicKey: Wallet.PublicKey,
|
||||
): CompletionResult<Map<ByteArray, ByteArray>> {
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
val task = MultiSignHashTask(dataToSign, publicKey, twinKey?.getPairKey(publicKey.seedKey))
|
||||
|
||||
tangemSdk.startSessionWithRunnable(
|
||||
runnable = task,
|
||||
cardId = cardId,
|
||||
initialMessage = initialMessage,
|
||||
) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
signerCallback(
|
||||
TangemSignerResponse(
|
||||
totalSignedHashes = result.data.totalSignedHashes,
|
||||
remainingSignatures = result.data.remainingSignatures,
|
||||
isRing = result.data.batchId?.let(::isRing) ?: false,
|
||||
),
|
||||
)
|
||||
if (continuation.isActive) {
|
||||
continuation.resume(CompletionResult.Success(result.data.signatures))
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure ->
|
||||
if (continuation.isActive) {
|
||||
continuation.resume(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class TangemSignerResponse(
|
||||
|
|
|
|||
|
|
@ -490,6 +490,7 @@ internal class DefaultTangemSdkManager(
|
|||
activationInput = activationInput,
|
||||
coroutineScope = this,
|
||||
),
|
||||
cardId = activationInput.cardId,
|
||||
initialMessage = Message(resources.getStringSafe(R.string.initial_message_tap_header)),
|
||||
)
|
||||
}
|
||||
|
|
@ -502,6 +503,7 @@ internal class DefaultTangemSdkManager(
|
|||
runnable = VisaCustomerWalletApproveTask(
|
||||
visaDataForApprove = visaDataForApprove,
|
||||
),
|
||||
cardId = visaDataForApprove.customerWalletCardId,
|
||||
initialMessage = Message(resources.getStringSafe(R.string.initial_message_tap_header)),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package com.tangem.tap.domain.tasks
|
||||
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.CompletionCallback
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.operations.CommandResponse
|
||||
import com.tangem.operations.sign.MultipleSignCommand
|
||||
import com.tangem.operations.sign.SignData
|
||||
|
||||
class TangemMultiSignHashResponse(
|
||||
val signatures: Map<ByteArray, ByteArray>,
|
||||
val totalSignedHashes: Int?,
|
||||
val remainingSignatures: Int?,
|
||||
val batchId: String?,
|
||||
) : CommandResponse
|
||||
|
||||
class MultiSignHashTask(
|
||||
private val dataToSign: List<SignData>,
|
||||
private val publicKey: Wallet.PublicKey,
|
||||
private val pairWalletPublicKey: ByteArray?,
|
||||
) : CardSessionRunnable<TangemMultiSignHashResponse> {
|
||||
|
||||
override fun run(session: CardSession, callback: CompletionCallback<TangemMultiSignHashResponse>) {
|
||||
MultipleSignCommand(dataToSign, publicKey.seedKey).run(session) { response ->
|
||||
when (response) {
|
||||
is CompletionResult.Success -> {
|
||||
val card = session.environment.card
|
||||
callback(
|
||||
CompletionResult.Success(
|
||||
TangemMultiSignHashResponse(
|
||||
signatures = response.data.associate { it.walletPublicKey to it.signature },
|
||||
totalSignedHashes = response.data.last().totalSignedHashes,
|
||||
remainingSignatures = card?.wallet(publicKey.seedKey)?.remainingSignatures,
|
||||
batchId = card?.batchId,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
when {
|
||||
response.error is TangemSdkError.WalletNotFound && pairWalletPublicKey != null -> {
|
||||
sign(session, pairWalletPublicKey, callback)
|
||||
}
|
||||
else -> callback(CompletionResult.Failure(response.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sign(
|
||||
session: CardSession,
|
||||
publicKey: ByteArray,
|
||||
callback: CompletionCallback<TangemMultiSignHashResponse>,
|
||||
) {
|
||||
MultipleSignCommand(dataToSign, publicKey).run(session) { response ->
|
||||
when (response) {
|
||||
is CompletionResult.Success -> {
|
||||
val card = session.environment.card
|
||||
callback(
|
||||
CompletionResult.Success(
|
||||
TangemMultiSignHashResponse(
|
||||
signatures = response.data.associate { it.walletPublicKey to it.signature },
|
||||
totalSignedHashes = response.data.last().totalSignedHashes,
|
||||
remainingSignatures = card?.wallet(publicKey)?.remainingSignatures,
|
||||
batchId = card?.batchId,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
callback(CompletionResult.Failure(response.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,12 +4,15 @@ import com.squareup.moshi.Json
|
|||
import com.squareup.moshi.JsonClass
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.visa.model.VisaCardActivationStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class UserWalletSensitiveInformation(
|
||||
@Json(name = "wallets")
|
||||
val wallets: List<CardDTO.Wallet>,
|
||||
@Json(name = "visaCardActivationStatus")
|
||||
val visaCardActivationStatus: VisaCardActivationStatus? = null,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
|
|||
import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation
|
||||
|
||||
internal val UserWallet.sensitiveInformation: UserWalletSensitiveInformation
|
||||
get() = UserWalletSensitiveInformation(scanResponse.card.wallets)
|
||||
get() = UserWalletSensitiveInformation(
|
||||
wallets = scanResponse.card.wallets,
|
||||
visaCardActivationStatus = scanResponse.visaCardActivationStatus,
|
||||
)
|
||||
|
||||
internal val UserWallet.publicInformation: UserWalletPublicInformation
|
||||
get() = UserWalletPublicInformation(
|
||||
|
|
@ -19,6 +22,7 @@ internal val UserWallet.publicInformation: UserWalletPublicInformation
|
|||
card = scanResponse.card.copy(
|
||||
wallets = emptyList(),
|
||||
),
|
||||
visaCardActivationStatus = null,
|
||||
),
|
||||
hasBackupError = hasBackupError,
|
||||
)
|
||||
|
|
@ -45,6 +49,7 @@ internal fun UserWallet.updateWith(sensitiveInformation: UserWalletSensitiveInfo
|
|||
card = scanResponse.card.copy(
|
||||
wallets = sensitiveInformation.wallets,
|
||||
),
|
||||
visaCardActivationStatus = sensitiveInformation.visaCardActivationStatus,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -70,5 +75,6 @@ internal fun UserWallet.lock(): UserWallet = copy(
|
|||
card = scanResponse.card.copy(
|
||||
wallets = emptyList(),
|
||||
),
|
||||
visaCardActivationStatus = null,
|
||||
),
|
||||
)
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package com.tangem.tap.features.details.redux
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed class DetailsAction : Action {
|
||||
|
|
@ -27,7 +27,7 @@ sealed class DetailsAction : Action {
|
|||
}
|
||||
|
||||
data class CheckBiometricsStatus(
|
||||
val lifecycleScope: LifecycleCoroutineScope,
|
||||
val coroutineScope: CoroutineScope,
|
||||
) : AppSettings()
|
||||
|
||||
data object EnrollBiometrics : AppSettings()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tap.features.details.redux
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
|
|
@ -22,6 +21,7 @@ import com.tangem.tap.store
|
|||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
|
@ -67,7 +67,7 @@ class DetailsMiddleware {
|
|||
}
|
||||
}
|
||||
is DetailsAction.AppSettings.CheckBiometricsStatus -> {
|
||||
observeBiometricsStatusChanges(action.lifecycleScope)
|
||||
observeBiometricsStatusChanges(action.coroutineScope)
|
||||
}
|
||||
is DetailsAction.AppSettings.EnrollBiometrics -> {
|
||||
enrollBiometrics()
|
||||
|
|
@ -90,7 +90,7 @@ class DetailsMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private fun observeBiometricsStatusChanges(lifecycleScope: LifecycleCoroutineScope) {
|
||||
private fun observeBiometricsStatusChanges(scope: CoroutineScope) {
|
||||
val needEnrollBiometricsFlow = flow {
|
||||
do {
|
||||
val needEnrollBiometrics = runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull()
|
||||
|
|
@ -108,7 +108,7 @@ class DetailsMiddleware {
|
|||
.onEach { needEnrollBiometrics ->
|
||||
store.dispatchWithMain(DetailsAction.AppSettings.BiometricsStatusChanged(needEnrollBiometrics))
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
.launchIn(scope)
|
||||
.saveIn(checkBiometricsStatusJobHolder)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
package com.tangem.tap.features.details.ui.appcurrency
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class AppCurrencySelectorFragment : ComposeFragment() {
|
||||
|
||||
@Inject
|
||||
override lateinit var uiDependencies: UiDependencies
|
||||
|
||||
private val viewModel: AppCurrencySelectorViewModel by viewModels()
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
NavigationBar3ButtonsScrim()
|
||||
AppCurrencySelectorScreen(
|
||||
modifier = modifier,
|
||||
state = uiState,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.tap.features.details.ui.appcurrency
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
|
||||
import com.tangem.tap.features.details.ui.appcurrency.api.AppCurrencySelectorComponent
|
||||
import com.tangem.tap.features.details.ui.appcurrency.model.AppCurrencySelectorModel
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
internal class DefaultAppCurrencySelectorComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: Unit,
|
||||
) : AppCurrencySelectorComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: AppCurrencySelectorModel = getOrCreateModel()
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val uiState by model.uiState.collectAsStateWithLifecycle()
|
||||
NavigationBar3ButtonsScrim()
|
||||
AppCurrencySelectorScreen(
|
||||
modifier = modifier,
|
||||
state = uiState,
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : AppCurrencySelectorComponent.Factory {
|
||||
override fun create(context: AppComponentContext, params: Unit): DefaultAppCurrencySelectorComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.tap.features.details.ui.appcurrency.api
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
|
||||
interface AppCurrencySelectorComponent : ComposableContentComponent {
|
||||
|
||||
interface Factory : ComponentFactory<Unit, AppCurrencySelectorComponent>
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.features.details.ui.appcurrency.di
|
||||
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.tap.features.details.ui.appcurrency.DefaultAppCurrencySelectorComponent
|
||||
import com.tangem.tap.features.details.ui.appcurrency.api.AppCurrencySelectorComponent
|
||||
import com.tangem.tap.features.details.ui.appcurrency.model.AppCurrencySelectorModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface AppCurrencySelectorFeatureModule {
|
||||
|
||||
@Binds
|
||||
fun bindFactory(impl: DefaultAppCurrencySelectorComponent.Factory): AppCurrencySelectorComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(AppCurrencySelectorModel::class)
|
||||
fun bindModel(model: AppCurrencySelectorModel): Model
|
||||
}
|
||||
|
|
@ -1,35 +1,38 @@
|
|||
package com.tangem.tap.features.details.ui.appcurrency
|
||||
package com.tangem.tap.features.details.ui.appcurrency.model
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.domain.appcurrency.GetAvailableCurrenciesUseCase
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.SelectAppCurrencyUseCase
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.features.details.ui.appcurrency.AppCurrencySelectorIntents
|
||||
import com.tangem.tap.features.details.ui.appcurrency.AppCurrencySelectorState
|
||||
import com.tangem.tap.features.details.ui.appcurrency.AppCurrencySelectorStateHolder
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
internal class AppCurrencySelectorViewModel @Inject constructor(
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class AppCurrencySelectorModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getAvailableCurrenciesUseCase: GetAvailableCurrenciesUseCase,
|
||||
private val selectAppCurrencyUseCase: SelectAppCurrencyUseCase,
|
||||
private val router: AppRouter,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : ViewModel(), AppCurrencySelectorIntents {
|
||||
) : Model(), AppCurrencySelectorIntents {
|
||||
|
||||
private val stateController = AppCurrencySelectorStateHolder(
|
||||
intents = this,
|
||||
onSubscription = { fetchCurrencies() },
|
||||
stateFlowScope = viewModelScope,
|
||||
stateFlowScope = modelScope,
|
||||
)
|
||||
|
||||
val uiState: StateFlow<AppCurrencySelectorState> = stateController.stateFlow
|
||||
|
|
@ -47,7 +50,7 @@ internal class AppCurrencySelectorViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onCurrencyClick(currency: AppCurrencySelectorState.Currency) {
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
modelScope.launch(dispatchers.io) {
|
||||
selectAppCurrencyUseCase(currency.id)
|
||||
.onRight {
|
||||
analyticsEventHandler.send(
|
||||
|
|
@ -63,7 +66,7 @@ internal class AppCurrencySelectorViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun fetchCurrencies() {
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
modelScope.launch(dispatchers.io) {
|
||||
val availableCurrencies = getAvailableCurrenciesUseCase()
|
||||
.onRight(stateController::updateStateWithAvailableCurrencies)
|
||||
.getOrNull()
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package com.tangem.tap.features.details.ui.appsettings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class AppSettingsFragment : ComposeFragment() {
|
||||
|
||||
@Inject
|
||||
override lateinit var uiDependencies: UiDependencies
|
||||
|
||||
@Inject
|
||||
lateinit var appCurrencyRepository: AppCurrencyRepository
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
val viewModel = hiltViewModel<AppSettingsViewModel>().apply {
|
||||
LocalLifecycleOwner.current.lifecycle.addObserver(observer = this)
|
||||
}
|
||||
val state by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
AppSettingsScreen(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
onBackClick = {
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.tangem.tap.features.details.ui.appsettings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.essenty.lifecycle.doOnResume
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.ui.appsettings.api.AppSettingsComponent
|
||||
import com.tangem.tap.features.details.ui.appsettings.model.AppSettingsModel
|
||||
import com.tangem.tap.store
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
internal class DefaultAppSettingsComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: Unit,
|
||||
) : AppSettingsComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: AppSettingsModel = getOrCreateModel()
|
||||
|
||||
init {
|
||||
|
||||
doOnResume { model.onResume() }
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
AppSettingsScreen(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
onBackClick = {
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : AppSettingsComponent.Factory {
|
||||
override fun create(context: AppComponentContext, params: Unit): DefaultAppSettingsComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -2,13 +2,13 @@ package com.tangem.tap.features.details.ui.appsettings.analytics
|
|||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsItemsFactory
|
||||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsScreenState
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
import javax.inject.Inject
|
||||
|
||||
@ViewModelScoped
|
||||
@ModelScoped
|
||||
internal class AppSettingsItemsAnalyticsSender @Inject constructor(
|
||||
private val analyticsHandler: AnalyticsEventHandler,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.tap.features.details.ui.appsettings.api
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
|
||||
interface AppSettingsComponent : ComposableContentComponent {
|
||||
|
||||
interface Factory : ComponentFactory<Unit, AppSettingsComponent>
|
||||
}
|
||||
|
|
@ -5,9 +5,8 @@ import androidx.compose.foundation.layout.Arrangement
|
|||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -20,7 +19,6 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsItemsFactory
|
||||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsScreenState.Item
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
internal fun SettingsButtonItem(item: Item.Button, modifier: Modifier = Modifier) {
|
||||
Surface(
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@ package com.tangem.tap.features.details.ui.appsettings.components
|
|||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -22,7 +21,6 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsItemsFactory
|
||||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsScreenState.Item
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
internal fun SettingsCardItem(item: Item.Card, modifier: Modifier = Modifier) {
|
||||
Surface(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import android.content.res.Configuration
|
|||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.features.details.ui.appsettings.di
|
||||
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.tap.features.details.ui.appsettings.DefaultAppSettingsComponent
|
||||
import com.tangem.tap.features.details.ui.appsettings.api.AppSettingsComponent
|
||||
import com.tangem.tap.features.details.ui.appsettings.model.AppSettingsModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface AppSettingsFeatureModule {
|
||||
|
||||
@Binds
|
||||
fun bindFactory(impl: DefaultAppSettingsComponent.Factory): AppSettingsComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(AppSettingsModel::class)
|
||||
fun bindModel(model: AppSettingsModel): Model
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
package com.tangem.tap.features.details.ui.appsettings
|
||||
package com.tangem.tap.features.details.ui.appsettings.model
|
||||
|
||||
import androidx.lifecycle.*
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
|
|
@ -20,12 +22,15 @@ import com.tangem.tap.features.details.redux.AppSetting
|
|||
import com.tangem.tap.features.details.redux.AppSettingsState
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsDialogsFactory
|
||||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsItemsFactory
|
||||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsScreenState
|
||||
import com.tangem.tap.features.details.ui.appsettings.analytics.AppSettingsItemsAnalyticsSender
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
|
@ -34,8 +39,10 @@ import org.rekotlin.StoreSubscriber
|
|||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@HiltViewModel
|
||||
internal class AppSettingsViewModel @Inject constructor(
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class AppSettingsModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val appCurrencyRepository: AppCurrencyRepository,
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val canUseBiometryUseCase: CanUseBiometryUseCase,
|
||||
|
|
@ -44,9 +51,7 @@ internal class AppSettingsViewModel @Inject constructor(
|
|||
private val appThemeModeRepository: AppThemeModeRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val appSettingsItemsAnalyticsSender: AppSettingsItemsAnalyticsSender,
|
||||
) : ViewModel(),
|
||||
StoreSubscriber<DetailsState>,
|
||||
DefaultLifecycleObserver {
|
||||
) : Model(), StoreSubscriber<DetailsState> {
|
||||
|
||||
private val itemsFactory = AppSettingsItemsFactory()
|
||||
private val dialogsFactory = AppSettingsDialogsFactory()
|
||||
|
|
@ -82,11 +87,12 @@ internal class AppSettingsViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onResume(owner: LifecycleOwner) {
|
||||
store.dispatch(DetailsAction.AppSettings.CheckBiometricsStatus(owner.lifecycleScope))
|
||||
fun onResume() {
|
||||
store.dispatch(DetailsAction.AppSettings.CheckBiometricsStatus(modelScope))
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
store.unsubscribe(subscriber = this)
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +231,7 @@ internal class AppSettingsViewModel @Inject constructor(
|
|||
.saveIn(appCurrencyUpdatesJobHolder)
|
||||
}
|
||||
|
||||
private fun bootstrapBiometricsUpdates() = viewModelScope.launch {
|
||||
private fun bootstrapBiometricsUpdates() = modelScope.launch {
|
||||
val state = AppSettingsState(
|
||||
saveWallets = walletsRepository.shouldSaveUserWalletsSync(),
|
||||
saveAccessCodes = settingsRepository.shouldSaveAccessCodes(),
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class CardSettingsFragment : ComposeFragment() {
|
||||
|
||||
@Inject
|
||||
override lateinit var uiDependencies: UiDependencies
|
||||
|
||||
private val viewModel: CardSettingsViewModel by viewModels()
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
val state by viewModel.screenState.collectAsStateWithLifecycle()
|
||||
|
||||
CardSettingsScreen(modifier = modifier, state = state)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.tap.features.details.ui.cardsettings.api.CardSettingsComponent
|
||||
import com.tangem.tap.features.details.ui.cardsettings.model.CardSettingsModel
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultCardSettingsComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: CardSettingsComponent.Params,
|
||||
) : CardSettingsComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: CardSettingsModel = getOrCreateModel(params)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.screenState.collectAsStateWithLifecycle()
|
||||
|
||||
CardSettingsScreen(modifier = modifier, state = state)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : CardSettingsComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: CardSettingsComponent.Params,
|
||||
): DefaultCardSettingsComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings.api
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
interface CardSettingsComponent : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, CardSettingsComponent>
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings.coderecovery
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AccessCodeRecoveryFragment : ComposeFragment() {
|
||||
|
||||
private val viewModel: AccessCodeRecoveryViewModel by viewModels()
|
||||
|
||||
@Inject
|
||||
override lateinit var uiDependencies: UiDependencies
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
val state by viewModel.screenState.collectAsStateWithLifecycle()
|
||||
|
||||
AccessCodeRecoveryScreen(
|
||||
state = state,
|
||||
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings.coderecovery
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.ui.cardsettings.coderecovery.api.AccessCodeRecoveryComponent
|
||||
import com.tangem.tap.features.details.ui.cardsettings.coderecovery.model.AccessCodeRecoveryModel
|
||||
import com.tangem.tap.store
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
internal class DefaultAccessCodeRecoveryComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: Unit,
|
||||
) : AccessCodeRecoveryComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: AccessCodeRecoveryModel = getOrCreateModel()
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.screenState.collectAsStateWithLifecycle()
|
||||
|
||||
AccessCodeRecoveryScreen(
|
||||
state = state,
|
||||
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : AccessCodeRecoveryComponent.Factory {
|
||||
override fun create(context: AppComponentContext, params: Unit): DefaultAccessCodeRecoveryComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings.coderecovery.api
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
|
||||
interface AccessCodeRecoveryComponent : ComposableContentComponent {
|
||||
|
||||
interface Factory : ComponentFactory<Unit, AccessCodeRecoveryComponent>
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings.coderecovery.di
|
||||
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.tap.features.details.ui.cardsettings.coderecovery.DefaultAccessCodeRecoveryComponent
|
||||
import com.tangem.tap.features.details.ui.cardsettings.coderecovery.api.AccessCodeRecoveryComponent
|
||||
import com.tangem.tap.features.details.ui.cardsettings.coderecovery.model.AccessCodeRecoveryModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface AccessCodeRecoveryFeatureModule {
|
||||
|
||||
@Binds
|
||||
fun bindFactory(impl: DefaultAccessCodeRecoveryComponent.Factory): AccessCodeRecoveryComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(AccessCodeRecoveryModel::class)
|
||||
fun bindModel(model: AccessCodeRecoveryModel): Model
|
||||
}
|
||||
|
|
@ -1,29 +1,33 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings.coderecovery
|
||||
package com.tangem.tap.features.details.ui.cardsettings.coderecovery.model
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.ui.cardsettings.coderecovery.AccessCodeRecoveryScreenState
|
||||
import com.tangem.tap.features.details.ui.cardsettings.domain.CardSettingsInteractor
|
||||
import com.tangem.tap.features.details.ui.common.utils.isAccessCodeRecoveryEnabled
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
internal class AccessCodeRecoveryViewModel @Inject constructor(
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class AccessCodeRecoveryModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val cardSettingsInteractor: CardSettingsInteractor,
|
||||
) : ViewModel() {
|
||||
) : Model() {
|
||||
|
||||
private val scannedScanResponse = cardSettingsInteractor.scannedScanResponse.value
|
||||
?: error("Scan response is null")
|
||||
|
|
@ -47,7 +51,7 @@ internal class AccessCodeRecoveryViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun saveChanges() = viewModelScope.launch {
|
||||
private fun saveChanges() = modelScope.launch {
|
||||
val isEnabled = screenState.value.enabledSelection
|
||||
|
||||
tangemSdkManager
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings.di
|
||||
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.tap.features.details.ui.cardsettings.api.CardSettingsComponent
|
||||
import com.tangem.tap.features.details.ui.cardsettings.DefaultCardSettingsComponent
|
||||
import com.tangem.tap.features.details.ui.cardsettings.model.CardSettingsModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface CardSettingsFeatureModule {
|
||||
|
||||
@Binds
|
||||
fun bindFactory(impl: DefaultCardSettingsComponent.Factory): CardSettingsComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(CardSettingsModel::class)
|
||||
fun bindModel(model: CardSettingsModel): Model
|
||||
}
|
||||
|
|
@ -1,16 +1,15 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings
|
||||
package com.tangem.tap.features.details.ui.cardsettings.model
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.routing.bundle.unbundle
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
|
|
@ -20,7 +19,6 @@ import com.tangem.domain.models.scan.CardDTO
|
|||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
|
|
@ -29,13 +27,16 @@ import com.tangem.tap.common.extensions.dispatchDialogShow
|
|||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.domain.extensions.signedHashesCount
|
||||
import com.tangem.tap.features.details.ui.cardsettings.CardInfo
|
||||
import com.tangem.tap.features.details.ui.cardsettings.CardSettingsScreenState
|
||||
import com.tangem.tap.features.details.ui.cardsettings.api.CardSettingsComponent
|
||||
import com.tangem.tap.features.details.ui.cardsettings.domain.CardSettingsInteractor
|
||||
import com.tangem.tap.features.details.ui.common.utils.*
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.wallet.R
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
|
@ -43,22 +44,24 @@ import timber.log.Timber
|
|||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@HiltViewModel
|
||||
internal class CardSettingsViewModel @Inject constructor(
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class CardSettingsModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val scanCardProcessor: ScanCardProcessor,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val cardSettingsInteractor: CardSettingsInteractor,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel() {
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<CardSettingsComponent.Params>()
|
||||
|
||||
private var previousBiometricsRequestPolicy: Boolean = false
|
||||
|
||||
private val userWalletId = savedStateHandle.get<Bundle>(AppRoute.CardSettings.USER_WALLET_ID_KEY)
|
||||
?.unbundle(UserWalletId.serializer())
|
||||
?: error("User wallet ID is required for CardSettingsViewModel")
|
||||
private val userWalletId = params.userWalletId
|
||||
|
||||
val screenState: MutableStateFlow<CardSettingsScreenState> = MutableStateFlow(getInitialState())
|
||||
|
||||
|
|
@ -68,10 +71,11 @@ internal class CardSettingsViewModel @Inject constructor(
|
|||
cardSettingsInteractor.scannedScanResponse
|
||||
.filterNotNull()
|
||||
.onEach(::updateCardDetails)
|
||||
.launchIn(viewModelScope)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
// Restore the previous value of access code request policy
|
||||
cardSdkConfigRepository.isBiometricsRequestPolicy = previousBiometricsRequestPolicy
|
||||
}
|
||||
|
|
@ -96,7 +100,7 @@ internal class CardSettingsViewModel @Inject constructor(
|
|||
onBackClick = ::onBackClick,
|
||||
)
|
||||
|
||||
private fun scanCard() = viewModelScope.launch {
|
||||
private fun scanCard() = modelScope.launch {
|
||||
scanCardProcessor.scan(
|
||||
analyticsSource = com.tangem.core.analytics.models.AnalyticsParam.ScreensSources.Settings,
|
||||
allowsRequestAccessCodeFromRepository = true,
|
||||
|
|
@ -217,7 +221,7 @@ internal class CardSettingsViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun changeAccessCode() = viewModelScope.launch {
|
||||
private fun changeAccessCode() = modelScope.launch {
|
||||
val scanResponse = requireNotNull(cardSettingsInteractor.scannedScanResponse.value) { "Scan response is null" }
|
||||
|
||||
when (val result = tangemSdkManager.setAccessCode(scanResponse.card.cardId)) {
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.tangem.tap.features.details.ui.resetcard
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.ui.resetcard.api.ResetCardComponent
|
||||
import com.tangem.tap.features.details.ui.resetcard.model.ResetCardModel
|
||||
import com.tangem.tap.store
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultResetCardComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: ResetCardComponent.Params,
|
||||
) : ResetCardComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: ResetCardModel = getOrCreateModel(params)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.screenState.collectAsStateWithLifecycle()
|
||||
|
||||
ResetCardScreen(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : ResetCardComponent.Factory {
|
||||
override fun create(context: AppComponentContext, params: ResetCardComponent.Params): DefaultResetCardComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package com.tangem.tap.features.details.ui.resetcard
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class ResetCardFragment : ComposeFragment() {
|
||||
|
||||
@Inject
|
||||
override lateinit var uiDependencies: UiDependencies
|
||||
|
||||
private val viewModel: ResetCardViewModel by viewModels()
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
val state by viewModel.screenState.collectAsStateWithLifecycle()
|
||||
|
||||
ResetCardScreen(
|
||||
state = state,
|
||||
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.tap.features.details.ui.resetcard.api
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
interface ResetCardComponent : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val cardId: String,
|
||||
val isActiveBackupStatus: Boolean,
|
||||
val backupCardsCount: Int,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, ResetCardComponent>
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.features.details.ui.resetcard.di
|
||||
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.tap.features.details.ui.resetcard.DefaultResetCardComponent
|
||||
import com.tangem.tap.features.details.ui.resetcard.api.ResetCardComponent
|
||||
import com.tangem.tap.features.details.ui.resetcard.model.ResetCardModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface ResetCardFeatureModule {
|
||||
|
||||
@Binds
|
||||
fun bindFactory(impl: DefaultResetCardComponent.Factory): ResetCardComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(ResetCardModel::class)
|
||||
fun bindModel(model: ResetCardModel): Model
|
||||
}
|
||||
|
|
@ -1,21 +1,19 @@
|
|||
package com.tangem.tap.features.details.ui.resetcard
|
||||
package com.tangem.tap.features.details.ui.resetcard.model
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.bundle.unbundle
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.card.DeleteSavedAccessCodesUseCase
|
||||
import com.tangem.domain.card.ResetCardUseCase
|
||||
import com.tangem.domain.card.ResetCardUserCodeParams
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.asLockable
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
|
|
@ -24,9 +22,12 @@ import com.tangem.tap.common.extensions.dispatchNavigationAction
|
|||
import com.tangem.tap.common.extensions.onUserWalletSelected
|
||||
import com.tangem.tap.features.details.ui.cardsettings.domain.CardSettingsInteractor
|
||||
import com.tangem.tap.features.details.ui.common.utils.getResetToFactoryDescription
|
||||
import com.tangem.tap.features.details.ui.resetcard.ResetCardDialog
|
||||
import com.tangem.tap.features.details.ui.resetcard.ResetCardScreenState
|
||||
import com.tangem.tap.features.details.ui.resetcard.api.ResetCardComponent
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
|
@ -35,8 +36,11 @@ import timber.log.Timber
|
|||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@HiltViewModel
|
||||
internal class ResetCardViewModel @Inject constructor(
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class ResetCardModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
paramsContainer: ParamsContainer,
|
||||
getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val resetCardUseCase: ResetCardUseCase,
|
||||
|
|
@ -45,13 +49,12 @@ internal class ResetCardViewModel @Inject constructor(
|
|||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val cardSettingsInteractor: CardSettingsInteractor,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel() {
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<ResetCardComponent.Params>()
|
||||
|
||||
// region Card-set specific data. All cards from single set have the same userWalletId and cardTypesResolver
|
||||
private val currentUserWalletId = savedStateHandle.get<Bundle>(AppRoute.ResetToFactory.USER_WALLET_ID)
|
||||
?.unbundle(UserWalletId.serializer())
|
||||
?: error("UserWalletId must be provided for ResetCardViewModel")
|
||||
private val currentUserWalletId = params.userWalletId
|
||||
|
||||
// Use only for card-specific data
|
||||
private val userWallet = getUserWalletUseCase(userWalletId = currentUserWalletId)
|
||||
|
|
@ -65,15 +68,11 @@ internal class ResetCardViewModel @Inject constructor(
|
|||
// endregion
|
||||
|
||||
// region Data of card that was scanned on CardSettings
|
||||
private val primaryCardId: String = savedStateHandle.get<String>(AppRoute.ResetToFactory.CARD_ID)
|
||||
?: error("CardId must be provided for ResetCardViewModel")
|
||||
private val primaryCardId: String = params.cardId
|
||||
|
||||
private val isActiveBackupPrimaryCard =
|
||||
savedStateHandle.get<Boolean>(AppRoute.ResetToFactory.IS_ACTIVE_BACKUP_STATUS)
|
||||
?: error("IsActiveBackupCard must be provided for ResetCardViewModel")
|
||||
private val isActiveBackupPrimaryCard = params.isActiveBackupStatus
|
||||
|
||||
private val primaryBackupCardsCount = savedStateHandle.get<Int>(AppRoute.ResetToFactory.BACKUP_CARDS_COUNT)
|
||||
?: error("CardCount must be provided for ResetCardViewModel")
|
||||
private val primaryBackupCardsCount = params.backupCardsCount
|
||||
// endregion
|
||||
|
||||
// TODO: move logic to separate domain entity
|
||||
|
|
@ -177,7 +176,7 @@ internal class ResetCardViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun makeFullReset() {
|
||||
viewModelScope.launch {
|
||||
modelScope.launch {
|
||||
resetCardUseCase(cardId = primaryCardId, params = currentUserCodeParams).onRight {
|
||||
deleteSavedAccessCodesUseCase(cardId = primaryCardId)
|
||||
val hasUserWallets = deleteWalletUseCase(userWalletId = currentUserWalletId).getOrElse {
|
||||
|
|
@ -203,7 +202,7 @@ internal class ResetCardViewModel @Inject constructor(
|
|||
private fun onContinueResetClick() {
|
||||
dismissDialog()
|
||||
|
||||
viewModelScope.launch {
|
||||
modelScope.launch {
|
||||
resetCardUseCase(
|
||||
cardNumber = resetBackupCardCount + 1,
|
||||
params = currentUserCodeParams,
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.tangem.tap.features.details.ui.securitymode
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.ui.securitymode.api.SecurityModeComponent
|
||||
import com.tangem.tap.features.details.ui.securitymode.model.SecurityModeModel
|
||||
import com.tangem.tap.store
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultSecurityModeComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: SecurityModeComponent.Params,
|
||||
) : SecurityModeComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: SecurityModeModel = getOrCreateModel(params)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.screenState.collectAsStateWithLifecycle()
|
||||
|
||||
SecurityModeScreen(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : SecurityModeComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: SecurityModeComponent.Params,
|
||||
): DefaultSecurityModeComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package com.tangem.tap.features.details.ui.securitymode
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class SecurityModeFragment : ComposeFragment() {
|
||||
|
||||
@Inject
|
||||
override lateinit var uiDependencies: UiDependencies
|
||||
|
||||
private val viewModel: SecurityModeViewModel by viewModels()
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
val state by viewModel.screenState.collectAsStateWithLifecycle()
|
||||
|
||||
SecurityModeScreen(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.tap.features.details.ui.securitymode.api
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
interface SecurityModeComponent : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, SecurityModeComponent>
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.features.details.ui.securitymode.di
|
||||
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.tap.features.details.ui.securitymode.DefaultSecurityModeComponent
|
||||
import com.tangem.tap.features.details.ui.securitymode.api.SecurityModeComponent
|
||||
import com.tangem.tap.features.details.ui.securitymode.model.SecurityModeModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface SecurityModeFeatureModule {
|
||||
|
||||
@Binds
|
||||
fun bindFactory(impl: DefaultSecurityModeComponent.Factory): SecurityModeComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(SecurityModeModel::class)
|
||||
fun bindModel(model: SecurityModeModel): Model
|
||||
}
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
package com.tangem.tap.features.details.ui.securitymode
|
||||
package com.tangem.tap.features.details.ui.securitymode.model
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
|
|
@ -15,18 +16,21 @@ import com.tangem.tap.features.details.redux.SecurityOption
|
|||
import com.tangem.tap.features.details.ui.cardsettings.domain.CardSettingsInteractor
|
||||
import com.tangem.tap.features.details.ui.common.utils.getAllowedSecurityOptions
|
||||
import com.tangem.tap.features.details.ui.common.utils.getCurrentSecurityOption
|
||||
import com.tangem.tap.features.details.ui.securitymode.SecurityModeScreenState
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
internal class SecurityModeViewModel @Inject constructor(
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class SecurityModeModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val cardSettingsInteractor: CardSettingsInteractor,
|
||||
) : ViewModel() {
|
||||
) : Model() {
|
||||
|
||||
private val scannedScanResponse = cardSettingsInteractor.scannedScanResponse.value
|
||||
?: error("Scan response is null")
|
||||
|
|
@ -62,7 +66,7 @@ internal class SecurityModeViewModel @Inject constructor(
|
|||
val cardId = scannedScanResponse.card.cardId
|
||||
val selectedOption = screenState.value.selectedSecurityMode
|
||||
|
||||
viewModelScope.launch {
|
||||
modelScope.launch {
|
||||
val result = when (selectedOption) {
|
||||
SecurityOption.LongTap -> tangemSdkManager.setLongTap(cardId)
|
||||
SecurityOption.PassCode -> tangemSdkManager.setPasscode(cardId)
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
package com.tangem.tap.features.details.ui.walletconnect
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.essenty.lifecycle.subscribe
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.tap.common.analytics.events.WalletConnect
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState
|
||||
import com.tangem.tap.features.details.ui.walletconnect.api.WalletConnectComponent
|
||||
import com.tangem.tap.store
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
internal class DefaultWalletConnectComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: Unit,
|
||||
) : WalletConnectComponent, AppComponentContext by appComponentContext, StoreSubscriber<WalletConnectState> {
|
||||
|
||||
private val model: WalletConnectModel = getOrCreateModel()
|
||||
|
||||
private var screenState: MutableState<WalletConnectScreenState> =
|
||||
mutableStateOf(model.updateState(store.state.walletConnectState))
|
||||
|
||||
init {
|
||||
lifecycle.subscribe(
|
||||
onCreate = {
|
||||
Analytics.send(WalletConnect.ScreenOpened())
|
||||
},
|
||||
onStart = {
|
||||
store.subscribe(this) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.walletConnectState == newState.walletConnectState
|
||||
}.select { it.walletConnectState }
|
||||
}
|
||||
},
|
||||
onStop = {
|
||||
store.unsubscribe(this)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun newState(state: WalletConnectState) {
|
||||
screenState.value = model.updateState(state)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
WalletConnectScreen(
|
||||
modifier = modifier,
|
||||
state = screenState.value,
|
||||
onBackClick = {
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : WalletConnectComponent.Factory {
|
||||
override fun create(context: AppComponentContext, params: Unit): DefaultWalletConnectComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
package com.tangem.tap.features.details.ui.walletconnect
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.tap.common.analytics.events.WalletConnect
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.rekotlin.StoreSubscriber
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class WalletConnectFragment : ComposeFragment(), StoreSubscriber<WalletConnectState> {
|
||||
|
||||
@Inject
|
||||
override lateinit var uiDependencies: UiDependencies
|
||||
|
||||
private val viewModel: WalletConnectViewModel by viewModels()
|
||||
|
||||
private var screenState: MutableState<WalletConnectScreenState>? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
Analytics.send(WalletConnect.ScreenOpened())
|
||||
lifecycle.addObserver(viewModel)
|
||||
screenState = mutableStateOf(viewModel.updateState(store.state.walletConnectState))
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
val state = screenState?.value ?: return
|
||||
WalletConnectScreen(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
onBackClick = {
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
store.subscribe(this) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.walletConnectState == newState.walletConnectState
|
||||
}.select { it.walletConnectState }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
override fun newState(state: WalletConnectState) {
|
||||
if (activity == null || view == null) return
|
||||
screenState?.value = viewModel.updateState(state)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +1,34 @@
|
|||
package com.tangem.tap.features.details.ui.walletconnect
|
||||
|
||||
import androidx.lifecycle.*
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.domain.qrscanning.models.SourceType
|
||||
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
internal class WalletConnectViewModel @Inject constructor(
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class WalletConnectModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val listenToQrScanningUseCase: ListenToQrScanningUseCase,
|
||||
private val clipboardManager: ClipboardManager,
|
||||
) : ViewModel(), DefaultLifecycleObserver {
|
||||
) : Model() {
|
||||
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
viewModelScope.launch {
|
||||
init {
|
||||
modelScope.launch {
|
||||
listenToQrScanningUseCase(SourceType.WALLET_CONNECT)
|
||||
.getOrElse { emptyFlow() }
|
||||
.flowWithLifecycle(owner.lifecycle, minActiveState = Lifecycle.State.CREATED)
|
||||
.collect { store.dispatch(WalletConnectAction.OpenSession(it)) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.tap.features.details.ui.walletconnect.api
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
|
||||
interface WalletConnectComponent : ComposableContentComponent {
|
||||
interface Factory : ComponentFactory<Unit, WalletConnectComponent>
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.features.details.ui.walletconnect.di
|
||||
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.tap.features.details.ui.walletconnect.DefaultWalletConnectComponent
|
||||
import com.tangem.tap.features.details.ui.walletconnect.WalletConnectModel
|
||||
import com.tangem.tap.features.details.ui.walletconnect.api.WalletConnectComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface WalletConnectFeatureModule {
|
||||
|
||||
@Binds
|
||||
fun bindFactory(impl: DefaultWalletConnectComponent.Factory): WalletConnectComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(WalletConnectModel::class)
|
||||
fun bindModel(model: WalletConnectModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package com.tangem.tap.features.home
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.arkivanov.essenty.lifecycle.subscribe
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.SystemBarsIconsDisposable
|
||||
import com.tangem.core.ui.utils.findActivity
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.home.api.HomeComponent
|
||||
import com.tangem.tap.features.home.compose.StoriesScreen
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.home.redux.HomeState
|
||||
import com.tangem.tap.store
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
internal class DefaultHomeComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: Unit,
|
||||
) : HomeComponent, AppComponentContext by appComponentContext, StoreSubscriber<HomeState> {
|
||||
|
||||
private val model: HomeModel = getOrCreateModel()
|
||||
|
||||
private var homeState: MutableState<HomeState> = mutableStateOf(store.state.homeState)
|
||||
|
||||
init {
|
||||
lifecycle.subscribe(
|
||||
onCreate = {
|
||||
store.dispatch(HomeAction.OnCreate)
|
||||
},
|
||||
onStart = {
|
||||
store.subscribe(subscriber = this) { state ->
|
||||
state
|
||||
.skipRepeats { oldState, newState -> oldState.homeState == newState.homeState }
|
||||
.select(AppState::homeState)
|
||||
}
|
||||
},
|
||||
onStop = {
|
||||
store.unsubscribe(this)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val activity = LocalContext.current.findActivity()
|
||||
BackHandler(onBack = activity::finish)
|
||||
SystemBarsIconsDisposable(darkIcons = false)
|
||||
StoriesScreen(
|
||||
homeState = homeState,
|
||||
onScanButtonClick = model::onScanClick,
|
||||
onShopButtonClick = model::onShopClick,
|
||||
onSearchTokensClick = model::onSearchClick,
|
||||
)
|
||||
}
|
||||
|
||||
override fun newState(state: HomeState) {
|
||||
homeState.value = state
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : HomeComponent.Factory {
|
||||
override fun create(context: AppComponentContext, params: Unit): DefaultHomeComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
package com.tangem.tap.features.home
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.components.SystemBarsIconsDisposable
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.home.compose.StoriesScreen
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.home.redux.HomeState
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.rekotlin.StoreSubscriber
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class HomeFragment : ComposeFragment(), StoreSubscriber<HomeState> {
|
||||
|
||||
@Inject
|
||||
override lateinit var uiDependencies: UiDependencies
|
||||
|
||||
private var homeState: MutableState<HomeState> = mutableStateOf(store.state.homeState)
|
||||
|
||||
private val viewModel by viewModels<HomeViewModel>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
store.dispatch(HomeAction.OnCreate)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
BackHandler(onBack = requireActivity()::finish)
|
||||
SystemBarsIconsDisposable(darkIcons = false)
|
||||
ScreenContent()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
store.subscribe(subscriber = this) { state ->
|
||||
state
|
||||
.skipRepeats { oldState, newState -> oldState.homeState == newState.homeState }
|
||||
.select(AppState::homeState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
override fun newState(state: HomeState) {
|
||||
if (activity == null || view == null) return
|
||||
|
||||
homeState.value = state
|
||||
}
|
||||
|
||||
@Suppress("TopLevelComposableFunctions")
|
||||
@Composable
|
||||
private fun ScreenContent() {
|
||||
StoriesScreen(
|
||||
homeState = homeState,
|
||||
onScanButtonClick = viewModel::onScanClick,
|
||||
onShopButtonClick = viewModel::onShopClick,
|
||||
onSearchTokensClick = viewModel::onSearchClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.home
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.google.firebase.analytics.ktx.analytics
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import com.tangem.common.routing.AppRoute
|
||||
|
|
@ -10,6 +9,8 @@ import com.tangem.core.analytics.Analytics
|
|||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
|
|
@ -30,7 +31,7 @@ import com.tangem.tap.features.home.redux.HIDE_PROGRESS_DELAY
|
|||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.home.redux.HomeMiddleware.NEW_BUY_WALLET_URL
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -38,8 +39,10 @@ import timber.log.Timber
|
|||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@HiltViewModel
|
||||
internal class HomeViewModel @Inject constructor(
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class HomeModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val scanCardProcessor: ScanCardProcessor,
|
||||
private val generateWalletNameUseCase: GenerateWalletNameUseCase,
|
||||
private val saveWalletUseCase: SaveWalletUseCase,
|
||||
|
|
@ -47,7 +50,7 @@ internal class HomeViewModel @Inject constructor(
|
|||
private val settingsRepository: SettingsRepository,
|
||||
private val urlOpener: UrlOpener,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : ViewModel() {
|
||||
) : Model() {
|
||||
|
||||
private val tangemErrorHandler = TangemTangemErrorsHandler(store)
|
||||
|
||||
|
|
@ -73,7 +76,7 @@ internal class HomeViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun scanCard() {
|
||||
viewModelScope.launch {
|
||||
modelScope.launch {
|
||||
cardSdkConfigRepository.isBiometricsRequestPolicy = settingsRepository.shouldSaveAccessCodes()
|
||||
|
||||
scanCardProcessor.scan(
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.tap.features.home.api
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
|
||||
interface HomeComponent : ComposableContentComponent {
|
||||
|
||||
interface Factory : ComponentFactory<Unit, HomeComponent>
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import androidx.compose.foundation.layout.Arrangement
|
|||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import androidx.compose.foundation.Image
|
|||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.features.home.di
|
||||
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.tap.features.home.DefaultHomeComponent
|
||||
import com.tangem.tap.features.home.HomeModel
|
||||
import com.tangem.tap.features.home.api.HomeComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface HomeFeatureModule {
|
||||
|
||||
@Binds
|
||||
fun bindFactory(impl: DefaultHomeComponent.Factory): HomeComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(HomeModel::class)
|
||||
fun bindModel(model: HomeModel): Model
|
||||
}
|
||||
|
|
@ -3,9 +3,9 @@ package com.tangem.tap.features.saveWallet.ui.components
|
|||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.features.welcome.di
|
||||
|
||||
import com.tangem.core.decompose.di.DecomposeComponent
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.tap.features.welcome.model.WelcomeModel
|
||||
import dagger.Binds
|
||||
|
|
@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey
|
|||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(DecomposeComponent::class)
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface ModelModule {
|
||||
|
||||
@Binds
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package com.tangem.tap.features.welcome.ui.components
|
|||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.datasource.local.preferences.AppPreferencesStore
|
|||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.lib.auth.ExpressAuthProvider
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.UUID
|
||||
|
|
@ -25,6 +26,17 @@ internal class DefaultExpressAuthProvider(
|
|||
}
|
||||
|
||||
override fun getRefCode(): String {
|
||||
val selectedUserWallet = userWalletsStore.selectedUserWalletOrNull ?: error("Can not get selected user wallet")
|
||||
|
||||
return when {
|
||||
isRing(selectedUserWallet) -> "ring"
|
||||
isChangeNow(selectedUserWallet) -> "ChangeNow"
|
||||
isPartner(selectedUserWallet) -> "partner"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun isRing(selectedUserWallet: UserWallet): Boolean {
|
||||
val addedWalletsWithRings = runBlocking {
|
||||
appPreferencesStore.getSyncOrDefault(
|
||||
key = PreferencesKeys.ADDED_WALLETS_WITH_RING_KEY,
|
||||
|
|
@ -32,9 +44,19 @@ internal class DefaultExpressAuthProvider(
|
|||
)
|
||||
}
|
||||
|
||||
val userWalletId = userWalletsStore.selectedUserWalletOrNull?.walletId?.stringValue
|
||||
?: error("No user id provided")
|
||||
return addedWalletsWithRings.contains(selectedUserWallet.walletId.stringValue)
|
||||
}
|
||||
|
||||
return if (addedWalletsWithRings.contains(userWalletId)) "ring" else ""
|
||||
private fun isChangeNow(selectedUserWallet: UserWallet): Boolean {
|
||||
return selectedUserWallet.scanResponse.card.batchId == BATCH_ID_CHANGENOW
|
||||
}
|
||||
|
||||
private fun isPartner(selectedUserWallet: UserWallet): Boolean {
|
||||
return selectedUserWallet.scanResponse.card.batchId == BATCH_ID_PARTNER
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val BATCH_ID_CHANGENOW = "BB000013"
|
||||
const val BATCH_ID_PARTNER = "AF990015"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package com.tangem.tap.network.auth
|
||||
|
||||
import com.tangem.datasource.api.common.visa.TangemVisaAuthProvider
|
||||
import com.tangem.domain.visa.model.VisaCardActivationStatus
|
||||
import com.tangem.domain.visa.model.getAuthHeader
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultVisaAuthProvider @Inject constructor(
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
) : TangemVisaAuthProvider {
|
||||
|
||||
override suspend fun getAuthHeader(cardId: String): String {
|
||||
val card = userWalletsListManager.userWalletsSync.firstOrNull { it.cardId == cardId }
|
||||
val status = card?.scanResponse?.visaCardActivationStatus as? VisaCardActivationStatus.Activated
|
||||
?: return "Error in the app!"
|
||||
return status.visaAuthTokens.getAuthHeader()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +1,17 @@
|
|||
package com.tangem.tap.network.auth.di
|
||||
|
||||
import com.tangem.datasource.api.common.AuthProvider
|
||||
import com.tangem.datasource.api.common.visa.TangemVisaAuthProvider
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.lib.auth.ExpressAuthProvider
|
||||
import com.tangem.lib.auth.StakeKitAuthProvider
|
||||
import com.tangem.tap.network.auth.*
|
||||
import com.tangem.tap.network.auth.DefaultAppVersionProvider
|
||||
import com.tangem.tap.network.auth.DefaultAuthProvider
|
||||
import com.tangem.tap.network.auth.DefaultExpressAuthProvider
|
||||
import com.tangem.tap.network.auth.DefaultStakeKitAuthProvider
|
||||
import com.tangem.tap.network.auth.DefaultVisaAuthProvider
|
||||
import com.tangem.utils.version.AppVersionProvider
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -55,13 +51,4 @@ internal class AuthModule {
|
|||
fun provideAppVersionProvider(): AppVersionProvider {
|
||||
return DefaultAppVersionProvider()
|
||||
}
|
||||
}
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface AuthBindModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindVisaAuthProvider(authStorage: DefaultVisaAuthProvider): TangemVisaAuthProvider
|
||||
}
|
||||
|
|
@ -153,6 +153,8 @@ internal val Blockchain.mercuryoNetwork: String?
|
|||
Blockchain.Bitrock, Blockchain.BitrockTestnet -> null
|
||||
Blockchain.Sonic, Blockchain.SonicTestnet -> null
|
||||
Blockchain.ApeChain, Blockchain.ApeChainTestnet -> null
|
||||
Blockchain.Scroll, Blockchain.ScrollTestnet -> null
|
||||
Blockchain.ZkLinkNova, Blockchain.ZkLinkNovaTestnet -> null
|
||||
Blockchain.KaspaTestnet -> null
|
||||
}
|
||||
}
|
||||
|
|
@ -154,5 +154,7 @@ internal val Blockchain.moonPaySupportedCurrency: MoonPaySupportedCurrency?
|
|||
Bitrock, BitrockTestnet -> null
|
||||
Sonic, SonicTestnet -> null
|
||||
ApeChain, ApeChainTestnet -> null
|
||||
Scroll, ScrollTestnet -> null
|
||||
ZkLinkNova, ZkLinkNovaTestnet -> null
|
||||
KaspaTestnet -> null
|
||||
}
|
||||
|
|
@ -33,7 +33,6 @@ import com.tangem.domain.wallets.repository.WalletsRepository
|
|||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
||||
import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter
|
||||
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
|
||||
import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
||||
|
|
@ -67,7 +66,6 @@ data class DaggerGraphState(
|
|||
val urlOpener: UrlOpener? = null,
|
||||
val shareManager: ShareManager? = null,
|
||||
val appRouter: AppRouter? = null,
|
||||
val pushNotificationsRouter: PushNotificationsRouter? = null,
|
||||
val transactionSignerFactory: TransactionSignerFactory? = null,
|
||||
val getUserCountryUseCase: GetUserCountryUseCase? = null,
|
||||
val onrampFeatureToggles: OnrampFeatureToggles? = null,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children
|
||||
import com.arkivanov.decompose.extensions.compose.stack.Children
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.arkivanov.decompose.router.stack.childStack
|
||||
import com.arkivanov.decompose.value.Value
|
||||
import com.arkivanov.decompose.value.observe
|
||||
import com.arkivanov.decompose.value.subscribe
|
||||
import com.arkivanov.essenty.backhandler.BackCallback
|
||||
import com.arkivanov.essenty.lifecycle.doOnDestroy
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
|
@ -64,7 +64,7 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
|||
appRouterConfig.componentRouter = router
|
||||
appRouterConfig.snackbarHandler = this
|
||||
|
||||
stack.observe(lifecycle) { stack ->
|
||||
stack.subscribe(lifecycle) { stack ->
|
||||
val stackItems = stack.items.map { it.configuration }
|
||||
|
||||
if (appRouterConfig.stack != stackItems) {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package com.tangem.tap.routing.utils
|
|||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
||||
import com.tangem.feature.referral.ReferralFragment
|
||||
import com.tangem.feature.qrscanning.QrScanningComponent
|
||||
import com.tangem.feature.referral.api.ReferralComponent
|
||||
import com.tangem.feature.stories.api.StoriesComponent
|
||||
import com.tangem.feature.walletsettings.component.WalletSettingsComponent
|
||||
import com.tangem.features.details.component.DetailsComponent
|
||||
|
|
@ -13,21 +13,21 @@ import com.tangem.features.managetokens.component.ManageTokensSource
|
|||
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
|
||||
import com.tangem.features.onboarding.v2.entry.OnboardingEntryComponent
|
||||
import com.tangem.features.onramp.component.*
|
||||
import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.features.staking.api.StakingComponent
|
||||
import com.tangem.features.pushnotifications.api.PushNotificationsComponent
|
||||
import com.tangem.features.send.api.SendComponent
|
||||
import com.tangem.features.swap.SwapComponent
|
||||
import com.tangem.features.staking.api.StakingComponent
|
||||
import com.tangem.features.tester.api.TesterRouter
|
||||
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
|
||||
import com.tangem.features.wallet.navigation.WalletRouter
|
||||
import com.tangem.tap.features.details.ui.appcurrency.AppCurrencySelectorFragment
|
||||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsFragment
|
||||
import com.tangem.tap.features.details.ui.cardsettings.CardSettingsFragment
|
||||
import com.tangem.tap.features.details.ui.cardsettings.coderecovery.AccessCodeRecoveryFragment
|
||||
import com.tangem.tap.features.details.ui.resetcard.ResetCardFragment
|
||||
import com.tangem.tap.features.details.ui.securitymode.SecurityModeFragment
|
||||
import com.tangem.tap.features.details.ui.walletconnect.WalletConnectFragment
|
||||
import com.tangem.tap.features.home.HomeFragment
|
||||
import com.tangem.features.tokendetails.TokenDetailsComponent
|
||||
import com.tangem.features.wallet.WalletEntryComponent
|
||||
import com.tangem.tap.features.details.ui.appcurrency.api.AppCurrencySelectorComponent
|
||||
import com.tangem.tap.features.details.ui.appsettings.api.AppSettingsComponent
|
||||
import com.tangem.tap.features.details.ui.cardsettings.api.CardSettingsComponent
|
||||
import com.tangem.tap.features.details.ui.cardsettings.coderecovery.api.AccessCodeRecoveryComponent
|
||||
import com.tangem.tap.features.details.ui.resetcard.api.ResetCardComponent
|
||||
import com.tangem.tap.features.details.ui.securitymode.api.SecurityModeComponent
|
||||
import com.tangem.tap.features.details.ui.walletconnect.api.WalletConnectComponent
|
||||
import com.tangem.tap.features.home.api.HomeComponent
|
||||
import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment
|
||||
import com.tangem.tap.features.onboarding.products.otherCards.OnboardingOtherCardsFragment
|
||||
import com.tangem.tap.features.onboarding.products.twins.ui.OnboardingTwinsFragment
|
||||
|
|
@ -58,14 +58,23 @@ internal class ChildFactory @Inject constructor(
|
|||
private val onboardingEntryComponentFactory: OnboardingEntryComponent.Factory,
|
||||
private val welcomeComponentFactory: WelcomeComponent.Factory,
|
||||
private val storiesComponentFactory: StoriesComponent.Factory,
|
||||
private val sendComponentFactory: SendComponent.Factory,
|
||||
private val stakingComponentFactory: StakingComponent.Factory,
|
||||
private val swapComponentFactory: SwapComponent.Factory,
|
||||
private val sendRouter: SendRouter,
|
||||
private val tokenDetailsRouter: TokenDetailsRouter,
|
||||
private val walletRouter: WalletRouter,
|
||||
private val qrScanningRouter: QrScanningRouter,
|
||||
private val homeComponentFactory: HomeComponent.Factory,
|
||||
private val tokenDetailsComponentFactory: TokenDetailsComponent.Factory,
|
||||
private val walletConnectComponentFactory: WalletConnectComponent.Factory,
|
||||
private val qrScanningComponentFactory: QrScanningComponent.Factory,
|
||||
private val accessCodeRecoveryComponentFactory: AccessCodeRecoveryComponent.Factory,
|
||||
private val cardSettingsComponentFactory: CardSettingsComponent.Factory,
|
||||
private val appCurrencySelectorComponentFactory: AppCurrencySelectorComponent.Factory,
|
||||
private val appSettingsComponentFactory: AppSettingsComponent.Factory,
|
||||
private val securityModeComponentFactory: SecurityModeComponent.Factory,
|
||||
private val resetCardComponentFactory: ResetCardComponent.Factory,
|
||||
private val referralComponentFactory: ReferralComponent.Factory,
|
||||
private val pushNotificationsComponentFactory: PushNotificationsComponent.Factory,
|
||||
private val walletComponentFactory: WalletEntryComponent.Factory,
|
||||
private val testerRouter: TesterRouter,
|
||||
private val pushNotificationRouter: PushNotificationsRouter,
|
||||
private val routingFeatureToggles: RoutingFeatureToggles,
|
||||
) {
|
||||
|
||||
|
|
@ -213,6 +222,16 @@ internal class ChildFactory @Inject constructor(
|
|||
componentFactory = storiesComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.CurrencyDetails -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = TokenDetailsComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
currency = route.currency,
|
||||
),
|
||||
componentFactory = tokenDetailsComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.Staking -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
|
|
@ -237,25 +256,119 @@ internal class ChildFactory @Inject constructor(
|
|||
componentFactory = swapComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.AccessCodeRecovery,
|
||||
is AppRoute.AppCurrencySelector,
|
||||
is AppRoute.Send -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = SendComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
currency = route.currency,
|
||||
transactionId = route.transactionId,
|
||||
amount = route.amount,
|
||||
tag = route.tag,
|
||||
destinationAddress = route.destinationAddress,
|
||||
),
|
||||
componentFactory = sendComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.Home -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = homeComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.WalletConnectSessions -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = walletConnectComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.QrScanning -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = QrScanningComponent.Params(
|
||||
source = route.source,
|
||||
networkName = route.networkName,
|
||||
),
|
||||
componentFactory = qrScanningComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.AccessCodeRecovery -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = accessCodeRecoveryComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.CardSettings -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = CardSettingsComponent.Params(userWalletId = route.userWalletId),
|
||||
componentFactory = cardSettingsComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.AppCurrencySelector -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = appCurrencySelectorComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.AppSettings -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = appSettingsComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.DetailsSecurity -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = SecurityModeComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
),
|
||||
componentFactory = securityModeComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.ResetToFactory -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = ResetCardComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
cardId = route.cardId,
|
||||
isActiveBackupStatus = route.isActiveBackupStatus,
|
||||
backupCardsCount = route.backupCardsCount,
|
||||
),
|
||||
componentFactory = resetCardComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.ReferralProgram -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = ReferralComponent.Params(route.userWalletId),
|
||||
componentFactory = referralComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.PushNotification -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = pushNotificationsComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.Wallet -> {
|
||||
createComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = walletComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.SaveWallet,
|
||||
is AppRoute.Send,
|
||||
is AppRoute.AppSettings,
|
||||
is AppRoute.CardSettings,
|
||||
is AppRoute.DetailsSecurity,
|
||||
is AppRoute.Home,
|
||||
is AppRoute.OnboardingNote,
|
||||
is AppRoute.OnboardingOther,
|
||||
is AppRoute.OnboardingTwins,
|
||||
is AppRoute.OnboardingWallet,
|
||||
is AppRoute.QrScanning,
|
||||
is AppRoute.ReferralProgram,
|
||||
is AppRoute.ResetToFactory,
|
||||
is AppRoute.Wallet,
|
||||
is AppRoute.WalletConnectSessions,
|
||||
is AppRoute.CurrencyDetails,
|
||||
is AppRoute.PushNotification,
|
||||
-> error("Unsupported route: $route")
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -271,22 +384,49 @@ internal class ChildFactory @Inject constructor(
|
|||
Child.Initial
|
||||
}
|
||||
is AppRoute.AccessCodeRecovery -> {
|
||||
route.asFragmentChild(Provider { AccessCodeRecoveryFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = accessCodeRecoveryComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.AppCurrencySelector -> {
|
||||
route.asFragmentChild(Provider { AppCurrencySelectorFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = appCurrencySelectorComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.SaveWallet -> {
|
||||
route.asFragmentChild(Provider { SaveWalletBottomSheetFragment() })
|
||||
}
|
||||
is AppRoute.Send -> {
|
||||
route.asFragmentChild(Provider { sendRouter.getEntryFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = SendComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
currency = route.currency,
|
||||
transactionId = route.transactionId,
|
||||
amount = route.amount,
|
||||
tag = route.tag,
|
||||
destinationAddress = route.destinationAddress,
|
||||
),
|
||||
componentFactory = sendComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.AppSettings -> {
|
||||
route.asFragmentChild(Provider { AppSettingsFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = appSettingsComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.CardSettings -> {
|
||||
route.asFragmentChild(Provider { CardSettingsFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = CardSettingsComponent.Params(userWalletId = route.userWalletId),
|
||||
componentFactory = cardSettingsComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.Details -> {
|
||||
route.asComponentChild(
|
||||
|
|
@ -296,7 +436,13 @@ internal class ChildFactory @Inject constructor(
|
|||
)
|
||||
}
|
||||
is AppRoute.DetailsSecurity -> {
|
||||
route.asFragmentChild(Provider { SecurityModeFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = SecurityModeComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
),
|
||||
componentFactory = securityModeComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.Disclaimer -> {
|
||||
route.asComponentChild(
|
||||
|
|
@ -306,7 +452,11 @@ internal class ChildFactory @Inject constructor(
|
|||
)
|
||||
}
|
||||
is AppRoute.Home -> {
|
||||
route.asFragmentChild(Provider { HomeFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = homeComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.ManageTokens -> {
|
||||
val source = when (route.source) {
|
||||
|
|
@ -334,13 +484,33 @@ internal class ChildFactory @Inject constructor(
|
|||
route.asFragmentChild(Provider { OnboardingWalletFragment() })
|
||||
}
|
||||
is AppRoute.QrScanning -> {
|
||||
route.asFragmentChild(Provider { qrScanningRouter.getEntryFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = QrScanningComponent.Params(
|
||||
source = route.source,
|
||||
networkName = route.networkName,
|
||||
),
|
||||
componentFactory = qrScanningComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.ReferralProgram -> {
|
||||
route.asFragmentChild(Provider { ReferralFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = ReferralComponent.Params(route.userWalletId),
|
||||
componentFactory = referralComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.ResetToFactory -> {
|
||||
route.asFragmentChild(Provider { ResetCardFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = ResetCardComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
cardId = route.cardId,
|
||||
isActiveBackupStatus = route.isActiveBackupStatus,
|
||||
backupCardsCount = route.backupCardsCount,
|
||||
),
|
||||
componentFactory = resetCardComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.Swap -> {
|
||||
route.asComponentChild(
|
||||
|
|
@ -356,13 +526,28 @@ internal class ChildFactory @Inject constructor(
|
|||
)
|
||||
}
|
||||
is AppRoute.Wallet -> {
|
||||
route.asFragmentChild(Provider { walletRouter.getEntryFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = walletComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.WalletConnectSessions -> {
|
||||
route.asFragmentChild(Provider { WalletConnectFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = walletConnectComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.CurrencyDetails -> {
|
||||
route.asFragmentChild(Provider { tokenDetailsRouter.getEntryFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = TokenDetailsComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
currency = route.currency,
|
||||
),
|
||||
componentFactory = tokenDetailsComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.Welcome -> {
|
||||
route.asFragmentChild(Provider { WelcomeFragment() })
|
||||
|
|
@ -382,7 +567,11 @@ internal class ChildFactory @Inject constructor(
|
|||
)
|
||||
}
|
||||
is AppRoute.PushNotification -> {
|
||||
route.asFragmentChild(Provider { pushNotificationRouter.entryFragment() })
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = Unit,
|
||||
componentFactory = pushNotificationsComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.WalletSettings -> {
|
||||
route.asComponentChild(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue